Отладка клиентов Google Data API: изучение трафика внутри вашей программы

Джеффри Скаддер, команда API данных Google
июнь 2007 г.

Введение

Иногда ничто не заменит наблюдения за тем, что происходит по сети. Это особенно актуально при написании программного обеспечения, которое использует веб-службы, такие как API данных Google, где многие операции включают выполнение HTTP-запросов. Когда ничего не помогает, вы можете убедиться, что ваша программа делает то, что вы ожидаете, увидев фактически переданные и полученные байты. Многие клиентские библиотеки для API данных Google имеют режим отладки, в котором отображается HTTP-трафик. Это особенно полезно, когда у вас нет доступа к анализаторам пакетов, таким как WireShark или Fiddler .

Я не могу сосчитать, сколько раз я мог поклясться, что моя программа была правильной, только чтобы обнаружить при проверке трассировки пакета лишний символ новой строки или неправильно названный заголовок HTTP. Программирование для веб-службы без просмотра HTTP-трафика может быть похоже на попытку вдеть нить в иголку с закрытыми глазами.

Однако вы можете оказаться в ситуации, когда анализатор пакетов недоступен или не подходит для работы с зашифрованными пакетами. Не бойтесь — вы можете обойти это ограничение, используя некоторые встроенные в программу механизмы ведения журналов. Используя эти средства ведения журналов, вы можете увидеть некоторые, если не все, обмениваемые данные, даже для зашифрованных данных HTTPS или удаленного исполняемого кода.

Для этой статьи я написал пример диагностического кода на трех языках с использованием клиентских библиотек Google Data API для Java , .NET и Python . В каждом примере я включаю ведение журнала или отладку, аутентифицируюсь с использованием клиентского входа, а затем получаю список своих таблиц Google и распечатываю их заголовки.

Джава

Вы можете использовать классы java.util.logging , чтобы установить уровни ведения журнала (и, следовательно, предоставить данные о трафике) для пары ключевых объектов в клиентской библиотеке. В приведенном ниже примере я решил просмотреть заголовки HTTP и действия синтаксического анализатора XML, чтобы получить полное представление о том, что передается по сети.

В клиентской библиотеке Google Data Java есть отдельные классы для обработки HTTP-запросов и анализа XML; таким образом, мне нужно создать два объекта Logger, по одному для каждого класса: com.google.gdata.client.http.HttpGDataRequest обрабатывает HTTP-трафик, а com.google.gdata.util.XmlParser отвечает за синтаксический анализ XML.

Экземпляры средства ведения журнала будут записывать действия для HttpGDataRequest и XmlParser , и вы можете контролировать уровень детализации выходных данных каждого средства ведения журнала. Для этой демонстрации я решил просмотреть все события, созданные объектами HttpGDataRequest и XmlParser .

После того, как я создал и настроил свои регистраторы, мне нужно сказать им, что делать, когда они получают событие от своих классов. На данный момент я хочу выводить всю информацию журнала на консоль, поэтому я создаю ConsoleHandler и добавляю его в оба моих регистратора.

Вот мой пример кода:

import com.google.gdata.client.spreadsheet.*;
import com.google.gdata.data.spreadsheet.*;
import com.google.gdata.util.*;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.*;

public class PrintSpreadsheetsWithLogging {
   
   
public static void main(String [] args) throws AuthenticationException,
                                                   
ServiceException, IOException {
       
// Configure the logging mechanisms.
       
Logger httpLogger = Logger.getLogger("com.google.gdata.client.http.HttpGDataRequest");
        httpLogger
.setLevel(Level.ALL);
       
Logger xmlLogger = Logger.getLogger("com.google.gdata.util.XmlParser");
        xmlLogger
.setLevel(Level.ALL);
       
// Create a log handler which prints all log events to the console.
       
ConsoleHandler logHandler = new ConsoleHandler();
        logHandler
.setLevel(Level.ALL);
        httpLogger
.addHandler(logHandler);
        xmlLogger
.addHandler (logHandler);
       
       
SpreadsheetService service = new SpreadsheetService("testing-loggingExampleApp-1");
        service
.setUserCredentials(email, password);
     
       
// Get a list of your spreadsheets.
        URL metafeedUrl
= new URL("http://spreadsheets.google.com/feeds/spreadsheets/private/full ");
       
SpreadsheetFeed feed = service.getFeed(metafeedUrl, SpreadsheetFeed.class);
     
       
// Print the title of each spreadsheet.
       
List spreadsheets = feed.getEntries();
       
for (int i = 0; i < spreadsheets.size(); i++) {
         
SpreadsheetEntry entry = (SpreadsheetEntry)spreadsheets.get(i);
         
System.out.println("\t" + entry.getTitle().getPlainText());
       
}
   
}
}

Когда вы запустите эту программу, вы увидите в консоли что-то вроде этого (некоторые менее интересные части я вырезал):

Jun 7, 2007 10:24:50 AM ...HttpGDataRequest setPrivateHeader
FINER: Authorization: <Not Logged>
Jun 7, 2007 10:24:50 AM ...HttpGDataRequest setHeader
FINER: User-Agent: ...
...
Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute
FINE: 200 OK
Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute
FINER: Date: Thu, 07 Jun 2007 17:25:24 GMT
Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute
FINER: null: HTTP/1.1 200 OK
Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute
FINER: Content-Type: application/atom+xml; charset=UTF-8
Jun 7, 2007 10:25:20 AM ...HttpGDataRequest execute
FINER: Last-Modified: Thu, 07 Jun 2007 17:25:22 GMT
...
Jun 7, 2007 10:25:20 AM ...XmlParser startElement
FINE: Start element id
Jun 7, 2007 10:25:20 AM ...XmlParser endElement
FINE: End element id
...
Jun 7, 2007 10:25:20 AM ...XmlParser startElement
FINE: Start element title
Jun 7, 2007 10:25:20 AM ...XmlParser startElement
FINER: Attribute type='text'
Jun 7, 2007 10:25:20 AM ...XmlParser endElement
FINE: End element title
...
Jun 7, 2007 10:25:20 AM ...XmlParser endElement
FINE: End element entry
...
Jun 7, 2007 10:25:20 AM ...XmlParser endElement
FINE: End element feed

Эти журналы могут быть довольно большими, поэтому вы можете быть более избирательны в настройке уровней регистраторов. Вы также можете создать FileHandler вместо ConsoleHandler , чтобы сохранить данные журнала для последующего использования.

Конечно, если вам не нравится Java, вы можете попробовать .NET.

.СЕТЬ

Для захвата HTTP-трафика в клиентской библиотеке .NET можно заменить фабрику запросов по умолчанию в клиенте на GDataLoggingRequestFactory .

Запросы HTTP в библиотеке .NET создаются GDataRequestFactory , которая находится внутри каждого объекта службы. Обычные фабрики запросов не ведут никакого ведения журнала, но GDataLoggingRequestFactory , который является подклассом GDataRequestFactory , имеет встроенное ведение журнала. Вы можете указать полный путь к файлу журнала, установив CombinedFileName .

После настройки фабрики запросов вам необходимо заменить фабрику запросов в объекте службы, установив RequestFactory объекта службы. Ваш код может выглядеть примерно так:

using System;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Spreadsheets;

namespace LogginTest
{
   
class Program
   
{
       
static void Main(string[] args)
       
{
           
SpreadsheetsService service = new SpreadsheetsService("-exampleApp-1");
            service
.setUserCredentials(email, password);

           
Google.GData.Client.GDataLoggingRequestFactory factory = new GDataLoggingRequestFactory("wise", "SpreadsheetsLoggingTest");
            factory
.MethodOverride = true;
            factory
.CombinedLogFileName = "c:\\temp\\xmllog.log";
           
Console.WriteLine("Log file name:" + factory.CombinedLogFileName);
           
            service
.RequestFactory = factory;

           
SpreadsheetQuery query = new SpreadsheetQuery();
           
SpreadsheetFeed feed = service.Query(query);

           
Console.WriteLine("Your spreadsheets:");
           
foreach (SpreadsheetEntry entry in feed.Entries)
           
{
               
Console.WriteLine(entry.Title.Text);
           
}

           
Console.ReadKey();
       
}
   
}
}

Результирующий файл журнала содержит XML-запросы и ответы. Вот сокращенный пример, который я отформатировал с помощью tidy .

<?xml version='1.0' encoding='utf-8'?>

<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'>
  <id>
  http://spreadsheets.google.com/feeds/spreadsheets/private/full</id>
  <updated>2007-06-07T22:05: 02.674Z</updated>
  <link rel='self' type='application/atom+xml'
  href='http://spreadsheets.google.com/feeds/spreadsheets/private/full'>

  </link>
  ...
  <entry>
    <updated>2007-03-28T17:28:57.250Z</updated>
    <category scheme=' http://schemas.google.com/spreadsheets/2006'
    term='http://schemas.google.com/spreadsheets/2006#spreadsheet'>
    <title type='text'>events</title>

    <content type='text'>events</content>
    ...
  </entry>
  <entry>
    <updated>2007-05-25T22:11:08.200Z</updated>

    <category scheme=' http://schemas.google.com/spreadsheets/2006'
    term='http://schemas.google.com/spreadsheets/2006#spreadsheet'>
    </category>
    <title type='text'>UnitTest</title>
    <content type='text'>UnitTest</content>
    ...
  </entry>

  ...
</feed>

Но, возможно, вам действительно нравятся языки сценариев, и вы предпочитаете использовать Python.

питон

Чтобы захватить HTTP-трафик в клиентской библиотеке Python, вы можете вывести трафик заголовков HTTP на консоль, включив режим отладки в HTTP-клиенте. У объекта службы есть член отладки, для которого вы можете установить значение True .

Установка для отладки значения true установит флаг отладки в базовом объекте HTTPRequest , который содержится в объекте службы.

Вот пример, который будет отображать заголовки HTTP, отправленные с сервера электронных таблиц, когда вы запрашиваете список своих электронных таблиц.

#!/usr/bin/python

import gdata.spreadsheet.service

client
= gdata.spreadsheet.service.SpreadsheetsService()
client
.debug = True

client
.ClientLogin(email, password)

feed
= client.GetSpreadsheetsFeed()

for entry in feed.entry:
 
print entry.title.text

И вы увидите что-то вроде этого на вашей консоли:

reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/atom+xml; charset=UTF-8
header: Last-Modified: Thu, 07 Jun 2007 18:22:35 GMT
header: Cache-Control: max-age=0, must-revalidate, private
header: Transfer-Encoding: chunked
...
header: Date: Thu, 07 Jun 2007 18:22:35 GMT
header: Server: GFE/1.3

При выполнении дополнительных операций, таких как вставка или обновление, вы увидите соответствующие данные запроса, отраженные на вашей консоли.

Заключение

В этом кратком руководстве показано, как можно добавить базовые функции ведения журналов в программу Java, .NET или Python, использующую клиентские библиотеки Google Data API. Эти методы могут быть полезны, если вам нужно отлаживать HTTP-обмены, но у вас нет доступа к анализатору пакетов. Я только поцарапал поверхность с этими примерами. Многие механизмы ведения журналов, присутствующие в этих языках, намного мощнее, чем показано здесь. Если вам нужна дополнительная информация о ведении журналов или API данных Google, ознакомьтесь со списком ресурсов ниже.

Клиентские библиотеки, описанные в этой статье, можно найти на следующих страницах:

Связанные элементы базы знаний:

Дискуссионные группы. У нас их довольно много, и их число будет увеличиваться по мере развертывания новых API данных Google. Мы активно следим за группами.

Если у вас есть вопросы или предложения, я буду рад услышать от вас. Зайдите в группу обсуждения и начните публиковать.