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

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

Введение

Иногда нет альтернативы наблюдению за тем, что проходит по сети. Это особенно актуально при написании программного обеспечения, использующего веб-сервисы, такие как API Google Data, где множество операций связано с HTTP-запросами. Если же всё остальное не помогает, вы можете убедиться, что ваша программа работает так, как и ожидалось, посмотрев фактические переданные и полученные байты. Многие клиентские библиотеки для API Google Data имеют режим отладки, отображающий 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

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

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

.СЕТЬ

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

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

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

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-клиенте. У объекта службы есть элемент debug, которому можно присвоить значение True .

Установка значения debug в 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-обмен, но у вас нет доступа к анализатору пакетов. Я лишь поверхностно рассмотрел эти примеры. Многие механизмы журналирования, представленные в этих языках, гораздо мощнее, чем представленные здесь. Если вам нужна дополнительная информация о журналировании или Google Data API, ознакомьтесь со списком ресурсов ниже.

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

Сопутствующие элементы базы знаний:

Группы для обсуждения: у нас их довольно много, и их будет становиться всё больше по мере внедрения новых API Google Data. Мы активно следим за группами.

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