2007 年 6 月
簡介
開發與網路服務互動的應用程式會帶來一組獨特的問題。造成使用者感到困擾的不尋常來源,並不知道收到的郵件到伺服器或收到的回應。其中最棘手的錯誤是因系統傳送的資料到伺服器,以及實際發生線上中斷而中斷。
本文介紹了多項工具,協助您在線路上取得清楚的資料,並從中獲得資料。這些工具通常稱為「封包探查器」,會擷取在網路介面中移動的所有網路封包。檢查這些封包的內容以及其傳送和接收順序是很實用的偵錯技巧。
範例:擷取公開資訊提供
我籌辦了一支慈善團體的慈善團體團活動,也為資訊會議、團隊募款活動和訓練搭車等活動建立了一個日曆。我們已將此日曆設為公開,方便小組成員和其他乘客查看日曆及參與活動。我也希望寄送包含近期活動的電子報,這樣就不必使用 Google 日曆網站複製資訊,而是使用 Google Calendar data API 查詢這個日曆並擷取活動。
Google Calendar API 說明文件說明如何使用 RESTful Google Data API,透過程式與我的日曆互動。(編輯者註意事項:自 v3 起,Google Calendar API 已不再使用 Google Data 格式)。首先,請按一下日曆設定頁面的 按鈕,取得日曆的活動資訊提供網址:
http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic
您可以使用 Google 日曆說明文件做為參考,以擷取和顯示這類日曆活動,其中 PUBLIC_FEED_URL
含有活動資訊提供網址。
CalendarService myService = new CalendarService("exampleCo-fiddlerExample-1"); final String PUBLIC_FEED_URL = "http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic"; URL feedUrl = new URL(PUBLIC_FEED_URL); CalendarEventFeed resultFeed = myService.getFeed(feedUrl, CalendarEventFeed.class); System.out.println("All events on your calendar:"); for (int i = 0; i < resultFeed.getEntries().size(); i++) { CalendarEventEntry entry = resultFeed.getEntries().get(i); System.out.println("\t" + entry.getTitle().getPlainText()); } System.out.println();
這將產生我的日曆上活動的基本清單:
All events on your calendar: MS150 Training ride Meeting with Nicole MS150 Information session
以上程式碼片段顯示了日曆活動的標題,但從伺服器收到的其餘資料呢?Java 用戶端程式庫無法輕鬆地將資訊提供或項目輸出為 XML 檔案,即使是 XML 檔案也不例外。與要求一併附上的 HTTP 標頭呢?查詢是否經過 Proxy 處理或重新導向?隨著作業流程越來越複雜,這些問題變得越來越重要 (尤其是出了點小狀況或問題出錯)。封包監視軟體會呈現網路流量的答案,以便回答這些問題。
tcpdump
tcpdump 是一個命令列工具,可在類似 Unix 的平台上運作,不過也有一個名為 WinDump 的 Windows 連接埠。就如同大部分的封包監視程式一樣,TCPdump 會將您的網路卡片進入超高模式 (需要超級使用者權限)。如要使用 tcpdump,只要指定要監聽的網路介面,網路流量就會傳送至 stdout:
sudo tcpdump -i eth0
如果執行這個指令,就會受到各種網路流量的無聊影響,其中有些活動無法辨識。您稍後可以將輸出結果轉送至某個檔案,並在後面加上 grep,不過這樣可能會產生一些非常龐大的檔案。大部分封包擷取軟體都內建各種篩選機制,因此您只需要擷取所需內容即可。
tcpdump 支援根據網路流量的特性篩選。舉例來說,您可以將伺服器主機名稱插入下列運算式,藉此指示 tcpdump 只擷取通訊埠 80 上的伺服器流量 (HTTP 訊息):
dst or src host <hostname> and port 80
針對符合篩選器運算式的每個封包,TCPdump 會顯示時間戳記、封包的來源和目的地以及多個 TCP 旗標。由於資訊顯示封包的傳送和接收順序,因此資訊十分重要。
查看封包內容通常也很有用。「-A」旗標會指示 tcpdump 以 ASCII 輸出每個封包,顯示 HTTP 標頭和郵件內文。「-s」標記可用來指定要顯示的位元組數 (「-s 0」表示完全不要截斷郵件內文)。
總而言之,我們會得到以下指令:
sudo tcpdump -A -s 0 -i eth0 dst or src host <hostname> and port 80
如果您執行這個指令,然後執行上述簡短的 .Java 範例,就會看到執行這項作業的所有網路通訊。您會在流量中看到 HTTP GET
要求:
22:22:30.870771 IP dellalicious.mshome.net.4520 > po-in-f99.google.com.80: P 1:360(359) ack 1 win 65535 E.....@....\...eH..c...P.=.....zP......GET /calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic HTTP/1.1 User-Agent: exampleCo-fiddlerExample-1 GCalendar-Java/1.0.6 GData-Java/1.0.10(gzip) Accept-Encoding: gzip Cache-Control: no-cache Pragma: no-cache Host: www.google.com Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive
您也會看到包含 Google 資料動態饋給的 200 OK
回應訊息。請注意,動態饋給會分到四個封包:
22:22:31.148789 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1:1431(1430) ack 360 win 6432 E...1 ..2.I.H..c...e.P.....z.=.:P..M...HTTP/1.1 200 OK Content-Type: application/atom+xml; charset=UTF-8 Cache-Control: max-age=0, must-revalidate, private Last-Modified: Mon, 11 Jun 2007 15:11:40 GMT Transfer-Encoding: chunked Date: Sun, 24 Jun 2007 02:22:10 GMT Server: GFE/1.3 13da <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://sc hemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005'><id>http ://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo gle.com/public/basic</id><updated>2007-06-11T15:11:40.000Z</updated><category sc heme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2 005#event'></category><title type='text'>MS150 Training Schedule</title><subtitl e type='text'>This calendar is public</subtitle><link rel='http://schemas.google .com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calend ar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic'></ link><link rel='self' type='application/atom+xml' href='http://www.google.com/ca lendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic ?max-results=25'></link><author><name>Lane LiaBraaten</name><email>api.lliabraa@ gmail.com</email></author><generator version='1.0' uri='http://www.google.com/ca lendar'>Google Calendar</generator><openSearch:totalRe 22:22:31.151501 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 1431:2861(1430) ack 360 win 6432 E...1!..2.I.H..c...e.P.......=.:P.. 2...sults>3</openSearch:totalResults><openSe arch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch :itemsPerPage><gd:where valueString=''></gd:where><gCal:timezone value='America/ Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/24v j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j 740hnj46744</id><published>2007-06-11T15:11:05.000Z</published><updated>2007-06- 11T15:11:05.000Z</updated><category scheme='http://schemas.google.com/g/2005#kin d' term='http://schemas.google.com/g/2005#event'></category><title type='text'>M S150 Training ride</title><summary type='html'>When: Sat Jun 9, 2007 7am to 10am &nbsp; PDT<br> <br>Event Status: confirmed</summary><conte nt type='text'>When: Sat Jun 9, 2007 7am to 10am&nbsp; PDT<br> <b r>Event Status: confirmed</content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid=ZGd0NDAwMjJjdWkyazNqNzQwaG5qNDY3 NDQgMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw' title='alternate'></link><link rel=' self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/24v j3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/dgt40022cui2k3j 740hnj46744'></link><author><name>MS150 Training Schedule</name></author><gCal:s endEventNotifications value='false'></gCal:sendEventNotifications></entry><entry ><id>http://www.google.com/cal 22:22:31.153097 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: . 2861:4291(1430) ack 360 win 6432 E...1#..2.I.H..c...e.P.......=.:P.. ....endar/feeds/24vj3m5pl125bh2ijbbneh953s%4 0group.calendar.google.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8</id><publishe d>2007-06-11T15:08:23.000Z</published><updated>2007-06-11T15:10:39.000Z</updated ><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.g oogle.com/g/2005#event'></category><title type='text'>Meeting with Nicole</title ><summary type='html'>When: Mon Jun 4, 2007 10am to 11am&nbsp; PDT<br> <br>Where: Conference Room B <br>Event Status: confirmed</summ ary><content type='text'>When: Mon Jun 4, 2007 10am to 11am&nbsp; PDT<br& gt; <br>Where: Conference Room B <br>Event Status: confirmed <br>Event Description: Discuss building cycling team for MS150</content><l ink rel='alternate' type='text/html' href='http://www.google.com/calendar/event? eid=NTFkOGtoNHMzYnBscW5iZjFscDZwMGtqcDggMjR2ajNtNXBsMTI1YmgyaWpiYm5laDk1M3NAZw' title='alternate'></link><link rel='self' type='application/atom+xml' href='http ://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.calendar.goo gle.com/public/basic/51d8kh4s3bplqnbf1lp6p0kjp8'></link><author><name>MS150 Trai ning Schedule</name></author><gCal:sendEventNotifications value='false'></gCal:s endEventNotifications></entry><entry><id>http://www.google.com/calendar/feeds/24 vj3m5pl125bh2ijbbneh953s%40group.calendar.google.com/public/basic/va41amq3r08dhh kpm3lc1abs2o</id><published>20 22:22:31.190244 IP po-in-f99.google.com.80 > dellalicious.mshome.net.4520: P 4291:5346(1055) ack 360 win 6432 E..G1$..2.K.H..c...e.P.....<.=.:P.. ....07-06-11T15:10:08.000Z</published><updat ed>2007-06-11T15:10:08.000Z</updated><category scheme='http://schemas.google.com /g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title ty pe='text'>MS150 Information session</title><summary type='html'>When: Wed Jun 6, 2007 4pm to Wed Jun 6, 2007 5pm&nbsp; PDT<br> <br>Event Statu s: confirmed</summary><content type='text'>When: Wed Jun 6, 2007 4pm to Wed Jun 6, 2007 5pm&nbsp; PDT<br> <br>Event Status: confirmed< /content><link rel='alternate' type='text/html' href='http://www.google.com/cale ndar/event?eid=dmE0MWFtcTNyMDhkaGhrcG0zbGMxYWJzMm8gMjR2ajNtNXBsMTI1YmgyaWpiYm5la Dk1M3NAZw' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/24vj3m5pl125bh2ijbbneh953s%40group.c alendar.google.com/public/basic/va41amq3r08dhhkpm3lc1abs2o'></link><author><name >MS150 Training Schedule</name></author><gCal:sendEventNotifications value='fals e'></gCal:sendEventNotifications></entry></feed>
此輸出結果包括所有 HTTP 標頭和內容,以及數個加密的 TCP 旗標。所有資料都列在這裡,但難以閱讀及理解。還有數種圖像工具可讓您輕鬆查看這項資料。
WireShark (原名 Ethereal)
![Wireshark 的螢幕畫面擷取](https://developers-dot-devsite-v2-prod.appspot.com/static/gdata/articles/support/otw/wireshark2.png?authuser=5&hl=zh-tw)
WireShark 可透過多種方式顯示網路流量。
WireShark 是一款透過 libpcap 建構的圖形工具,與 tcpdump 相同,而且適用於 Linux、Mac OS X 和 Windows。WireShark 的 GUI 支援多種解讀封包擷取資料並進行互動的方法。例如,從網路介面擷取封包時,封包會根據所使用的通訊協定以不同顏色顯示。您也可以按時間戳記、來源、目的地和通訊協定排序流量。
如果您選取封包清單中的任一列,Wireshark 會在使用者可理解的樹狀結構的封包標頭中顯示 IP、TCP 和其他通訊協定專屬資訊。這些資料也會顯示在 HEX 和 ASCII 的畫面底部。
WireShark 的視覺性質讓網路流量更容易理解,在大多數情況下,您還是可以篩選網路流量。WireShark 提供強大的篩選功能,還支援數百種通訊協定。
提示:如要查看可用通訊協定並建構複雜的篩選器,請按一下 WireShark 視窗頂端附近的 按鈕。
如要重新建立上述 tcpdump 範例中使用的篩選器,您可以在 WireShark 篩選器方塊中插入下列運算式:
ip.addr==<your IP address> && tcp.port==80
或運用 WireShark 對 HTTP 的瞭解:
ip.addr==<your IP address> && http
這麼做可篩選拍攝結果,只顯示與此日曆互動相關的封包。按一下各個封包即可查看內容並彙整交易。
提示:在其中一個封包上按一下滑鼠右鍵,然後選擇 [追蹤 TCP 串流],即可在單一視窗中依序顯示要求和回應。
WireShark 提供多種儲存擷取資訊的方法。您可以儲存一個、部分或所有封包。如果您正在檢視 TCP 串流,只要按一下 [另存新檔] 按鈕即可儲存相關的封包。您也可以在 tcpdump 擷取中匯入輸出內容,並在 WireShark 中查看。
問題:SSL 和加密作業
封包擷取工具的一個缺點是,無法查看透過 SSL 連線加密的資料。以上範例可存取公開的資訊提供,因此不需要使用 SSL。但是,如果範例存取了私人動態饋給,用戶端就必須透過需要安全資料傳輸層 (SSL) 連線的 Google 驗證服務進行驗證。
以下回應範例與上一個範例類似,但 CalendarService
會要求使用者的日曆中繼資訊提供,這是需要驗證的私人資訊提供。如要驗證,只要呼叫 setUserCredentials
方法即可。這個方法會觸發傳送至 ClientLogin 服務的 HTTPS 要求,並從回應中擷取驗證權杖。接著,CalendarService
物件會在所有後續要求中加入驗證權杖。
CalendarService myService = new CalendarService("exampleCo-fiddlerSslExample-1"); myService.setUserCredentials(username, userPassword); final String METAFEED_URL = "http://www.google.com/calendar/feeds/default"; URL feedUrl = new URL(METAFEED_URL); CalendarFeed resultFeed = myService.getFeed(feedUrl, CalendarFeed.class); System.out.println("Your calendars:"); for (int i = 0; i < resultFeed.getEntries().size(); i++) { CalendarEntry entry = resultFeed.getEntries().get(i); System.out.println("\t" + entry.getTitle().getPlainText()); } System.out.println();
驗證及存取私人 Google Data API 資訊提供所需的網路流量:
- 將使用者憑證提交給 ClientLogin 服務
- 將 HTTP
POST
傳送至 https://www.google.com/accounts/ClientLogin,並在郵件內文中使用下列參數:- 電子郵件 - 使用者的電子郵件地址。
- Passwd - 使用者的密碼。
- source (來源):識別您的用戶端應用程式。應採用 CompanyName-applicationName-versionID 的格式。例如使用 ExampleCo-FiddlerSSLExample-1。
- service - Google 日曆服務名稱為「cl」。
- 將 HTTP
- 接收授權權杖
- 如果驗證要求失敗,您會收到 HTTP 403 禁止狀態碼。
- 如果成功,服務的回應就會是 HTTP 200 OK 狀態碼,以及回應內文中的三個長英數字元代碼:
SID
、LSID
和Auth
。Auth
值是授權憑證。
- 要求私人日曆中繼資訊提供
- 將 HTTP
GET
傳送至 http://www.google.com/calendar/feeds/default,並使用以下標頭:
Authorization: GoogleLogin auth=<yourAuthToken>
- 將 HTTP
嘗試執行這個程式碼片段並查看 WireShark 中的網路流量 (使用「http || ssl」做為篩選器)。您會看到與交易相關的安全資料傳輸層 (SSL) 和傳輸層安全標準 (TLS) 封包,但「ClientLogin」要求和回應封包已在「Application Data」封包中加密。別擔心,接下來我們介紹一項能實際顯示這項加密資訊的工具。
Fiddler
Fiddler 是另一種圖形封包簡化工具,但其運作方式與目前呈現的工具大不相同。Fiddler 是您的應用程式與互動之遠端服務之間的 Proxy,可有效成為中間人。Fiddler 會與您應用程式和遠端網路服務建立 SSL 連線,先從一個端點解密流量,擷取純文字,然後重新加密流量,然後再傳送流量。很抱歉,Fidler 僅適用於 Windows 以及所有 Mac 和 Linux 使用者。
注意:SSL 支援需要 Fiddler 2 版和 .NET Framework 2.0 版。
您可透過 Session Inspector 分頁查看 Fiddler 中的網路流量。最適合用來偵錯 Google Data API 問題的子分頁:
- 標頭 - 以可收合的樹狀格式顯示 HTTP 標頭。
- Auth (驗證):顯示驗證標頭。
- 原始值 - 以 ASCII 文字顯示網路封包的內容
提示:按一下 Fiddler 視窗左下角的 圖示,即可開啟或關閉拍攝功能。
Fiddler 使用 .NET Framework 設定網路連線,將 Fiddler 用做 Proxy。也就是說,根據預設,您透過 Internet Explorer 或 .NET 程式碼建立的所有連線都會顯示在 Fiddler 中。不過,由於 Java 採用不同的方式設定 HTTP Proxy,因此系統不會顯示上述 Java 範例的流量。
在 Java 中,您可以使用系統屬性來設定 HTTP Proxy。Fiddler 的通訊埠是通訊埠 8888,因此安裝本機時,您可以新增下列幾行程式碼,讓 Java 程式碼使用 Fiddler 做為 HTTP 和 HTTPS 的 Proxy:
System.setProperty("http.proxyHost", "localhost"); System.setProperty("http.proxyPort", "8888"); System.setProperty("https.proxyHost", "localhost"); System.setProperty("https.proxyPort", "8888");
如果您使用這幾行程式碼執行範例,實際上實際上是從 Java 安全性套件取得謹慎的堆疊追蹤:
[java] Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
![Fiddler 的螢幕畫面擷取](https://developers-dot-devsite-v2-prod.appspot.com/static/gdata/articles/support/otw/fiddler.png?authuser=5&hl=zh-tw)
Fiddler 可以解密並顯示安全資料傳輸層 (SSL) 流量。
如果無法驗證來自安全資料傳輸層 (SSL) 連線中的伺服器傳回的憑證,就會發生這個錯誤。在這個例子中,不良憑證是來自 Fiddler,而且是一名中間人。Fiddler 會即時產生憑證,由於 Fiddler 並不是可信任的發卡機構,因此這些憑證會導致 Java 無法設定 SSL 連線。
注意:當您執行 Fiddler 時,使用 Internet Explorer 建立的任何安全資料傳輸層 (SSL) 連線都會觸發「安全性警示」,詢問您是否仍要改用 Spetchy 憑證。您可以按一下 [檢視憑證] 查看 Fiddler 產生的憑證。
那麼,該如何解決這個問題呢?基本上,您必須重新設定 Java 的安全性架構,才能信任所有憑證。幸好,您不需要重新發動輪盤就能體驗 Francis Labrie 的解決方案,並將 SSLUtilities.trustAllHttpsCertificates()
方法新增至上述範例。
將 Java 設定為使用 Fiddler 做為 Proxy 並停用預設憑證驗證之後,您可以執行範例,並查看所有以純文字傳輸的傳輸流量。不要竊取我的密碼!
請注意,這類驗證交易只是少部分 SSL 流量的範例。部分網路應用程式僅使用安全資料傳輸層 (SSL) 連線,因此偵錯 HTTP 流量會排除問題,而不必解密資料。
結語
Linux、Mac OS X 和 Windows 都支援 tcpdump。這款工具可協助您輕鬆找到所需內容,而且只需快速拍攝即可。不過,有些圖形工具能以容易理解的格式提供網路流量。相較於此處提及的格式,TCPdump 擁有更多選項和篩選功能。如需 tcpdump 功能的完整說明,請輸入「man tcpdump」,或是前往 tcpdump man page。
WireShark 也支援 Linux、Mac OS X 和 Windows。WireShark 內建支援數百種通訊協定,讓許多應用程式都可使用,不僅是 HTTP 偵錯。這個簡介幾乎無法刮開 WireShark 的眾多功能。如需更多資訊,請輸入「man 電匯」或造訪 WireShark 網站。
Fiddler 也有許多很棒的功能,但其優勢在於解密 SSL 流量的能力。如要瞭解詳情,請造訪 Fiddler2 網站。
這些封包稀少的應用程式是最適合使用工具的工具,觀測到的讀者則發現大家都完全免費!下次使用 Google API 時,如果遇到一些小事,請取下其中一個網路分析工具,然後仔細查看有線電線。如果找不到問題,您可以隨時將問題張貼到討論群組。附上相關的網路訊息,可幫助其他人瞭解並診斷您的特定問題。
祝你好運,祝你好運愉快!