HttpClient 獲取 Cookie 的一次踩坑實錄

fullstackyang發表於2017-09-14

在使用HttpClient進行抓取一些網頁的時候,經常會保留從伺服器端發回的Cookie資訊,以便發起其他需要這些Cookie的請求。大多數情況下,我們使用內建的cookie策略,便能夠方便直接地獲取這些cookie。

下面的一小段程式碼,就是訪問http://www.baidu.com,並獲取對應的cookie:

列印結果

但是也有一些網站返回的cookie並不一定完全符合規範,例如下面這個例子,從列印出的header中可以看到,這個cookie中的Expires屬性是時間戳形式,並不符合標準的時間格式,因此,httpclient對於cookie的處理失效,最終無法獲取到cookie,並且發出了一條警告資訊:“Invalid ‘expires’ attribute: 1505204523”

雖然我們可以利用header的資料,重新構造一個cookie出來,也有很多人確實也是這麼做的,但這種方法不夠優雅,那麼如何解決這個問題?網上相關的資料又很少,所以就只能先從官方文件入手。在官方文件3.4小節custom cookie policy中講到允許自定義的cookie策略,自定義的方法是實現CookieSpec介面,並通過CookieSpecProvider來完成在httpclient中的初始化和註冊策略例項的工作。好了,關鍵的線索在於CookieSpec介面,我們來看一下它的原始碼:

在原始碼中我們發現了一個parse方法,看註釋就知道正是這個方法,將Set-Cookie的header資訊解析為Cookie物件,自然地再瞭解一下在httplcient中的預設實現DefaultCookieSpec,限於篇幅,原始碼就不貼了。在預設的實現中,DefaultCookieSpec主要的工作是判斷header中Cookie規範的型別,然後再呼叫具體的某一個實現。像上述這種Cookie,最終是交由NetscapeDraftSpec的例項來做解析,而在NetscapeDraftSpec的原始碼中,定義了預設的expires時間格式為“EEE, dd-MMM-yy HH:mm:ss z”

到這裡已經比較清楚了,我們只需要將Cookie中expires的時間轉換為正確的格式,然後再送入預設的解析器就可以了。

解決方法:

  1. 自定義一個CookieSpec類,繼承DefaultCookieSpec
  2. 重寫parser方法
  3. 將Cookie中的expires轉換為正確的時間格式
  4. 呼叫預設的解析方法

實現如下(URL就不公開了,已經隱去)

再次執行,順利地列印出正確的結果,完美!

本文也發我的個人部落格:fullstackyang

相關文章