偵錯 Google Data API 用戶端:從程式內部探索流量

Google Data API 團隊 Jeffrey Scudder
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 流量,您可以將用戶端中的預設要求 Factory 替換為 GDataLoggingRequestFactory

.NET 程式庫中的 HTTP 要求是由每個 Service 物件內的 GDataRequestFactory 所建立。一般要求工廠不會執行任何記錄作業,但 GDataLoggingRequestFactory (GDataRequestFactory 的子類別) 內建記錄功能。您可以設定 CombinedFileName,指定記錄檔的完整路徑。

設定要求 Factory 後,您需要設定服務物件的 RequestFactory,以取代服務物件中的要求 Factory。程式碼可能如下所示:

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

將偵錯設為 true 時,服務物件所含基礎 HTTPRequest 物件中的偵錯標記也會一併設為 true。

以下範例會回應您要求試算表清單時,從試算表伺服器傳送的 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 Data API 推出,討論群組也會增加。我們會積極監控群組。

如有任何問題或建議,歡迎與我們聯絡。加入討論群組並開始發文。