1. 程式人生 > >《HttpClient 官方文件》第三章 HTTP 狀態管理

《HttpClient 官方文件》第三章 HTTP 狀態管理

原文連結 譯者[陳志軍]

通常 HTTP 被設計為無狀態,面向請求/響應的協議,對於有一些邏輯相關的請求/響應交換的有狀態會話沒有特別的規定。正當 HTTP 協議越來越流行和被認可,越來越多之前沒有打算使用它的系統,現在也開始為了應用程式而使用它。例如電子商務應用的內容傳輸。因此,支援 HTTP 狀態管理變得非常有必要。
NetScape(網景公司),曾經引領網頁客戶端和伺服器端軟體的發展,在他們的產品中基於專有的規範,提供了 HTTP 狀態管理的支援。之後,NetScape 嘗試通過釋出規範草案來標準化這種機制。這些努力通過 RFC 標準促進了正式的規範定義。但是,狀態管理在很多應用程式中仍然支援 Netscape 的草案而不相容官方的標準。很多Web瀏覽器的主要開發人員覺得有必要保留這些極大地促進標準相容性的草案。

3.1. HTTP cookies

一個 HTTP cookie 是 HTTP 代理或者目標伺服器保持會話和交流狀態資訊的一個令牌或者短資料包。Netscape 工程師過去稱它為 “魔力 cookie”,一個非常有粘力的名字。
HttpClient 使用 Cookie 介面來表示一個抽象 cookie 令牌。在 HTTP 中,簡單的形式是指一個鍵/值對。通常一個 HTTP cookie 也包含一系列的屬性,cookie 提供的屬性有例如一個域名是否可用,源伺服器上指定的url子集路徑,cookie 最長的有效時間等。
SetCookie 介面表示由源伺服器傳送給HTTP代理的響應頭中的Set-Cookie,以此來維持一個會話狀態。
ClientCookie介面繼承自 Cookie 介面並且自身擴充套件了客戶端特有的功能,例如從源伺服器中恢復原始的 cookie。這對於生成 Cookie 的頭資訊是非常重要的,因為一些特殊的 cookie 規範需要Cookie頭資訊中必須包含特定的屬性,這些需要在 Set-Cookie 頭中定義。下面是一些建立客戶端 cookie 的例項:

BasicClientCookie cookie = new BasicClientCookie("name", "value");
// Set effective domain and path attributes
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
// Set attributes exactly as sent by the server
cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");

3.2. Cookie 規範

CookieSpec 介面定義了一個 cookie 管理規範。下面這些是 cookie 管理規範強制的:

  • Set-Cookie 的解析規則
  • 驗證解析 cookies的規則
  • 給定的主機,埠和源路徑來格式化Cookie 頭資訊

HttpClient 附帶了一些 CookieSpec 的實現規範:

  • Standard strict: State management policy compliant with the syntax and semantics of the well-behaved profile defined by RFC on6265, section 4.
  • Standard: State management policy compliant with a more relaxed profile defined by RFC 6265, section 4 intended for interoperability with existing servers that do not conform to the well behaved profile.
  • Netscape draft (obsolete): This policy conforms to the original draft specification published by Netscape Communications. It should be avoided unless absolutely necessary for compatibility with legacy code.
  • RFC 2965 (obsolete): State management policy compliant with the obsolete state management specification defined by RFC 2965. Please do not use in new applications.
  • RFC 2109 (obsolete): State management policy compliant with the obsolete state management specification defined by RFC 2109. Please do not use in new applications.
  • Browser compatibility (obsolete): This policy strives to closely mimic the (mis)behavior of older versions of browser applications such as Microsoft Internet Explorer and Mozilla FireFox. Please do not use in new applications.
  • Default: Default cookie policy is a synthetic policy that picks up either RFC 2965, RFC 2109 or Netscape draft compliant implementation based on properties of cookies sent with the HTTP response (such as version attribute, now obsolete). This policy will be deprecated in favor of the standard (RFC 6265 compliant) implementation in the next minor release of HttpClient.
  • Ignore cookies: All cookies are ignored.

在新的應用實現中,強烈建議使用Standard 或者 Standard strict兩種規範。過時的規範僅僅在一些遺留的系統上為了相容性而使用。支援的過時規範會在下一個釋出的 HttpClient 主要版本中移除。

3.3. 選擇 cookie 策略

Cookie 策略可以在 HTTP 客戶端中設定,如果需要也可以在 HTTP 請求中重寫。

RequestConfig globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultRequestConfig(globalConfig)
.build();
RequestConfig localConfig = RequestConfig.copy(globalConfig)
.setCookieSpec(CookieSpecs.STANDARD_STRICT)
.build();
HttpGet httpGet = new HttpGet("/");
httpGet.setConfig(localConfig);

3.4. 自定義 cookie 策略

為了實現自定義 cookie 策略你必須實現一個 CookieSpec 介面,建立 CookieSpecProvider 的實現類,用它來初始化自定義的規範和 HttpClient 的註冊工廠。一旦自定義策略被註冊,它就可以像標準的 cookie 規範一些樣使用。

PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();

Registry r = RegistryBuilder.create()
.register(CookieSpecs.DEFAULT,
new DefaultCookieSpecProvider(publicSuffixMatcher))
.register(CookieSpecs.STANDARD,
new RFC6265CookieSpecProvider(publicSuffixMatcher))
.register("easy", new EasySpecProvider())
.build();

RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec("easy")
.build();

CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(requestConfig)
.build();

3.5. Cookie 持久化

HttpClient 可以和任何一個實現了CookieStore 介面的物理 cookie 一起使用。預設的 CookieStore 實現類是 BasicCookieStore,它是使用 java.utils.ArrayList 來實現的。當容器物件被進行垃圾回收時,儲存在BasicClientCookie中的Cookies物件也會丟失。如果必要的話,使用者可以提供一個複雜的實現。

// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Populate cookies if needed
BasicClientCookie cookie = new BasicClientCookie("name", "value");
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);
// Set the store
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.build();

3.6. HTTP 狀態管理和執行上下文

在HTTP請求執行過程中,HttpClient將下面相關狀態管理物件新增到執行的上下文中:

  • Lookup instance representing the actual cookie specification registry. The value of this attribute set in the local context takes precedence over the default one.
  • CookieSpec instance representing the actual cookie specification.
  • CookieOrigin instance representing the actual details of the origin server.
  • CookieStore instance representing the actual cookie store. The value of this attribute set in the local context takes precedence over the default one.

本地HttpContext物件可以用於在請求執行之前定製HTTP狀態管理的上下文,或者在請求執行後檢查它的狀態。開發者仍然可以使用分開的上下文來實現每一個使用者(或者每一個執行緒)的狀態管理。cookie 規範的註冊,在本地上下文中定義儲存的 cookie 優先於那些在 HTTP 客戶端設定的預設上下文。

CloseableHttpClient httpclient =

Lookup cookieSpecReg =
CookieStore cookieStore =

HttpClientContext context = HttpClientContext.create();
context.setCookieSpecRegistry(cookieSpecReg);
context.setCookieStore(cookieStore);
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);

// Cookie origin details
CookieOrigin cookieOrigin = context.getCookieOrigin();
// Cookie spec used
CookieSpec cookieSpec = context.getCookieSpec();