调试 Google 数据 API 客户端:探索程序的流量

Jeffrey Scudder,Google 数据 API 团队
2007 年 6 月

简介

有时候,无法比方查看传输的内容。在编写使用网络服务(如 Google Data API)的软件时尤其如此,其中许多操作都涉及到发出 HTTP 请求。 当所有其他方法都失败后,您可以通过查看实际传输的字节数和接收的字节数来验证程序是否按预期运行。Google Data API 的许多客户端库都有一个调试模式,可以显示 HTTP 流量。当您无法使用 WireSharkFiddler 等数据包嗅探器时,此功能特别有用。

我无法数步宣誓我的程序是正确的,只是在检查数据包轨迹后发现有多余的换行符或 HTTP 标头名称有误。在不查看 HTTP 流量的情况下针对网络服务进行编程,就像尝试封锁针头,让眼睛凝视着纸眼世界。

但是,您可能会发现自己遇到了数据包嗅探器不可用或不足以处理加密数据包的情况。不必担心,您可以利用一些程序内日志记录机制来规避此限制。通过利用这些日志记录工具,您可以查看部分(如果不是所有)交换的数据,即使对于加密的 HTTPS 数据或远程运行的代码也是如此。

在本文中,我使用适用于 Java.NETPython 的 Google Data API 客户端库编写了 3 种语言的示例诊断代码。在每个示例中,我都启用了日志记录或调试功能、使用客户端登录机制进行身份验证,然后获取了我的 Google 电子表格列表并输出了它们的标题。

Java

您可以使用 java.util.logging 类为客户端库中的几个关键对象设置日志记录级别(并因此公开流量数据)。在下面的示例中,我选择查看 HTTP 标头和 XML 解析器的活动,以全面了解通过网络传输的内容。

Google Data Java 客户端库具有单独的类来处理 HTTP 请求和 XML 解析;因此,我需要创建两个 Logger 对象,每个类各一个:com.google.gdata.client.http.HttpGDataRequest 负责处理 HTTP 流量,而 com.google.gdata.util.XmlParser 负责 XML 解析。

日志记录器实例将记录 HttpGDataRequestXmlParser 的活动,并且您可以控制每个日志记录器输出的详细程度。在本演示中,我已选择查看 HttpGDataRequestXmlParser 对象生成的所有事件。

创建并配置日志记录器后,我需要告诉他们在收到其课程中的事件时该怎么做。现在,我想将所有日志记录信息写入控制台,因此我创建了一个 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。

.NET

若要捕获 .NET 客户端库中的 HTTP 流量,您可以将客户端中的默认请求工厂替换为 GDataLoggingRequestFactory

.NET 库中的 HTTP 请求由每个 Service 对象内的 GDataRequestFactory 创建。常规请求工厂不执行任何日志记录,但 GDataLoggingRequestFactoryGDataRequestFactory 的子类)内置了日志记录。您可以通过设置 CombinedFileName 来指定日志文件的完整路径。

设置请求工厂后,您需要通过设置服务对象的 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。

Python

若要捕获 Python 客户端库中的 HTTP 流量,您可以通过在 HTTP 客户端中启用调试模式来回显控制台的 HTTP 标头流量。服务对象具有可设置为 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

当您执行其他操作(例如插入或更新)时,您会看到控制台中返回相应的请求数据。

总结

此简短教程说明了如何将基本日志记录功能添加到使用 Google Data API 客户端库的 Java、.NET 或 Python 程序中。如果您需要调试 HTTP 交换,但无权访问数据包嗅探器,这些技术非常有用。我只是通过这些示例不再简单地进行操作。这些语言中的许多日志记录机制比此处所示的功能要强大得多。如需了解有关日志记录或 Google Data API 的更多信息,请查看下面的资源列表。

本文涵盖的客户端库可在以下页面中找到:

相关知识库内容:

论坛:我们有不少论坛,随着更多 Google 数据 API 的推出,还将有更多论坛加入。我们会积极监控这些群体。

如果您有任何疑问或建议,请与我们联系。加入论坛并开始发帖。