Debugowanie klientów interfejsu API danych Google: analiza ruchu z Twojego programu

Jeffrey Scudder, zespół Google Data API
Czerwiec 2007 r.

Wprowadzenie

Czasem nie ma nic lepszego niż sprawdzenie, co dzieje się za przewodem. Jest to szczególnie widoczne podczas tworzenia oprogramowania, które korzysta z usług internetowych, takich jak interfejsy API danych Google, gdzie wiele operacji obejmuje żądania HTTP. Jeśli nic innego nie pomoże, możesz sprawdzić, czy program działa zgodnie z Twoimi oczekiwaniami, wyświetlając rzeczywiste i odebrane bajty. Wiele bibliotek klienta interfejsów API danych Google ma tryb debugowania, który wyświetla ruch HTTP. Jest to szczególnie przydatne, gdy nie masz dostępu do sniffera pakietów, takiego jak WireShark czy Fiddler.

Nie mogę zliczyć, ile razy zdarzało mi się oświadczyć, że mój program jest prawidłowy. Sprawdzałam tylko, czy po prześledzeniu śladu pakietu został dodany nowy znak nowego wiersza lub nieprawidłowy nagłówek HTTP. Programowanie w ramach usługi internetowej bez sprawdzania ruchu HTTP jest jak robienie nici z izolacją oczu i pisaniem.

Czasami jednak może się zdarzyć, że sniffer pakietów będzie niedostępny lub nieodpowiedni do obsługi zaszyfrowanych pakietów. Nie obawiaj się obchodzić tego ograniczenia dzięki korzystaniu z niektórych mechanizmów logowania w ramach programu. Dzięki tym narzędziom możesz zobaczyć niektóre lub nawet wszystkie dane wymiany, nawet w przypadku zaszyfrowanych danych HTTPS lub zdalnego uruchamiania kodu.

W tym artykule napisałem przykładowy kod diagnostyczny w 3 językach, korzystając z bibliotek klienta Google Data API w językach Java, .NET i Python. W każdym przykładzie włączam logowanie lub debugowanie, uwierzytelniam się przy użyciu loginu klienta, a następnie pobieram listę arkuszy kalkulacyjnych Google i drukuję ich tytuły.

Java

Klasy w java.util.logging umożliwiają ustawienie poziomów logowania (a w związku z tym ujawnienie danych o ruchu) dla kilku kluczowych obiektów w bibliotece klienta. W poniższym przykładzie chcę przyjrzeć się nagłówkom HTTP i aktywnościom parsera XML, aby zyskać pełny obraz tego, co dzieje się przez przewod.

Biblioteka klienta Java Google Data ma oddzielne klasy do obsługi żądań HTTP i analizy XML. Muszę więc utworzyć 2 obiekty Logger, po 1 dla każdej klasy: com.google.gdata.client.http.HttpGDataRequest obsługuje ruch HTTP, a za przeanalizowanie XML odpowiada com.google.gdata.util.XmlParser.

Instancje rejestratorów będą nagrywać działania dla HttpGDataRequest i XmlParser. Możesz kontrolować poziom szczegółowości danych wyjściowych każdego rejestratora. Na potrzeby tego demonstracji chcę wyświetlać wszystkie zdarzenia utworzone przez obiekty HttpGDataRequest i XmlParser.

Gdy utworzę i skonfiguruję rejestratorzy, muszę poinformować ich, co mają zrobić po otrzymaniu wydarzenia ze swoich zajęć. Na razie chcę zapisać wszystkie informacje dotyczące logowania w konsoli, więc utworzę ConsoleHandler i dodam je do obu rejestratorów.

Oto przykładowy kod:

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());
       
}
   
}
}

Gdy uruchomisz ten program, w konsoli zobaczysz coś takiego (fragmenty, które są mniej interesujące, są wycięte):

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

Logi mogą być dość duże, więc podczas ustawiania poziomów Rejestratorów warto uważać. Możesz też utworzyć FileHandler zamiast ConsoleHandler, aby przechowywać dane dziennika do późniejszego użycia.

Oczywiście, jeśli nie masz Javy, wypróbuj .NET.

.NET

Aby przechwytywać ruch HTTP w bibliotece klienta .NET, możesz zastąpić w klientze domyślną fabrykę żądania GDataLoggingRequestFactory.

Żądania HTTP w bibliotece .NET są tworzone przez obiekt GDataRequestFactory w każdym obiekcie usługi. Zwykłe fabryki żądań nie wykonują żadnych logów, ale GDataLoggingRequestFactory, który jest podklasą GDataRequestFactory, ma wbudowane logowanie. Możesz określić pełną ścieżkę pliku dziennika przez ustawienie CombinedFileName.

Po skonfigurowaniu fabryki żądania musisz zastąpić fabrykę żądania w obiekcie usługi, ustawiając RequestFactory obiektu usługi. Twój kod może wyglądać mniej więcej tak:

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();
       
}
   
}
}

Otrzymany plik dziennika zawiera żądania XML i odpowiedzi. Oto skrócony przykład, który został sformatowany przy użyciu atrybutu porządek.

<?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>

Ale jeśli na pewno znasz język skryptowy i wolisz Pythona,

Python

Aby przechwytywać ruch HTTP w bibliotece klienta Pythona, możesz powtórzyć ruch nagłówka HTTP w konsoli, włączając tryb debugowania w kliencie HTTP. Obiekt usługi ma członka debugowania, który można ustawić na True.

Jeśli ustawisz wartość debugowania na wartość „prawda”, flaga debugowania w objętym bazowym obiekcie HTTPRequest zawartym w obiekcie usługi zostanie ustawiona.

Oto przykład, który odczytuje nagłówki HTTP wysyłane z serwera arkuszy kalkulacyjnych, gdy prosisz o listę arkuszy kalkulacyjnych.

#!/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

W konsoli zobaczysz coś takiego:

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

Podczas wykonywania dodatkowych operacji, takich jak wstawianie lub aktualizowanie, w konsoli będą się pojawiać odpowiednie dane dotyczące żądań.

Podsumowanie

Ten krótki samouczek pokazuje, jak dodać podstawowe funkcje logowania do programu w języku Java, .NET lub Python, które korzystają z bibliotek klienta interfejsu Google Data API. Te metody mogą być pomocne, jeśli chcesz debugować wymiany HTTP, ale nie masz dostępu do sniffera pakietów. Dane zostały przedstawione wyłącznie na podstawie poniższych przykładów. Wiele mechanizmów logowania jest dostępnych w tych językach, ale ma znacznie większe możliwości. Jeśli chcesz dowiedzieć się więcej o logowaniu lub interfejsach API danych Google, zapoznaj się z listą zasobów poniżej.

Biblioteki klienta omówione w tym artykule znajdziesz na tych stronach:

Powiązane elementy bazowej wiedzy:

Grupy dyskusyjne: Jest ich całkiem sporo, a w miarę wprowadzania kolejnych interfejsów API danych Google będzie ich więcej. Monitorujemy te grupy.

Jeśli masz pytania lub sugestie, chętnie poznam Twoją opinię. Dołącz do grupy dyskusyjnej i zacznij publikować posty.