原始的HTTP是被設計為無狀態(tài)的,面向請求/響應的協(xié)議,沒有特殊規(guī)定有狀態(tài)的,貫穿一些邏輯相關的請求/響應交換的會話。由于HTTP協(xié)議變得越來越普及和受歡迎,越來越多的從前沒有打算使用它的系統(tǒng)也開始為應用程序來使用它,比如作為電子商務應用程序的傳輸方式。因此,支持狀態(tài)管理就變得非常必要了。
網(wǎng)景公司,一度成為Web客戶端和服務器軟件開發(fā)者的領導方向,在它們基于專有規(guī)范的產(chǎn)品中實現(xiàn)了對HTTP狀態(tài)管理的支持。之后,網(wǎng)景公司試圖通過發(fā)布規(guī)范草案來規(guī)范這種機制。它們的努力通過RFC標準跟蹤促成了這些規(guī)范定義。然而,在很多應用程序中的狀態(tài)管理仍然基于網(wǎng)景公司的草案而不兼容官方的規(guī)范。很多主要的Web瀏覽器開發(fā)者覺得有必要保留那些極大促進標準片段應用程序的兼容性。
3.1 HTTP cookies
Cookie是HTTP代理和目標服務器可以交流保持會話的狀態(tài)信息的令牌或短包。網(wǎng)景公司的工程師用它來指“魔法小甜餅”和粘住的名字。
HttpClient使用Cookie接口來代表抽象的cookie令牌。在它的簡單形式中HTTP的cookie幾乎是名/值對。通常一個HTTP的cookie也包含一些屬性,比如版本號,合法的域名,指定cookie應用所在的源服務器URL子集的路徑,cookie的最長有效時間。
SetCookie接口代表由源服務器發(fā)送給HTTP代理的響應中的頭部信息Set-Cookie來維持一個對話狀態(tài)。SetCookie2接口和指定的Set-Cookie2方法擴展了SetCookie。
SetCookie接口和額外的如獲取原始cookie屬性的能力,就像它們由源服務器指定的客戶端特定功能擴展了Cookie接口。這對生成Cookie頭部很重要,因為一些cookie規(guī)范需要。Cookie頭部應該包含在Set-Cookie或Set-Cookie2頭部中指定的特定屬性。
3.1.1 Cookie版本
這里有一個重新創(chuàng)建網(wǎng)景公司草案cookie示例:
BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");netscapeCookie.setVersion(0);netscapeCookie.setDomain(".mycompany.com");netscapeCookie.setPath("/");
這是一個重新創(chuàng)建標準cookie的示例。要注意符合標準的cookie必須保留由源服務器發(fā)送的所有屬性:
BasicClientCookie stdCookie = new BasicClientCookie("name", "value");stdCookie.setVersion(1);stdCookie.setDomain(".mycompany.com");stdCookie.setPath("/");stdCookie.setSecure(true);// 精確設置由服務器發(fā)送的屬性stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
這是一個重新創(chuàng)建Set-Cookie2兼容cookie的實例。要注意符合標準的cookie必須保留由源服務器發(fā)送的所有屬性:
BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value");stdCookie.setVersion(1);stdCookie.setDomain(".mycompany.com");stdCookie.setPorts(new int[] {80,8080});stdCookie.setPath("/");stdCookie.setSecure(true);// 精確設置由服務器發(fā)送的屬性stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
3.2 Cookie規(guī)范
- 解析的Set-Cookie規(guī)則還有可選的Set-Cookie2頭部信息。
- 驗證解析cookie的規(guī)則。
- 格式化給定主機的Cookie頭部信息,原始端口和路徑。
HttpClient附帶了一些CookieSpec的實現(xiàn):
- 網(wǎng)景公司草案:這個規(guī)范符合由網(wǎng)景通訊發(fā)布的原始草案規(guī)范。應當避免,除非有絕對的必要去兼容遺留代碼。
- RFC 2109:官方HTTP狀態(tài)管理規(guī)范并取代的老版本,被RFC 2965取代。
- RFC 2965:官方HTTP狀態(tài)管理規(guī)范。
- 瀏覽器兼容性:這個實現(xiàn)努力去密切模仿(mis)通用Web瀏覽器應用程序的實現(xiàn)。比如微軟的Internet Explorer和Mozilla的FireFox瀏覽器。
- 最佳匹配:’Meta’(元)cookie規(guī)范采用了一些基于又HTTP響應發(fā)送的cookie格式的cookie策略。它基本上聚合了以上所有的實現(xiàn)到以一個類中。
3.3 HTTP cookie和狀態(tài)管理參數(shù)
- 'http.protocol.cookie-datepatterns':定義了用于解析非標準的expires屬性的合法日期格式。只是對兼容不符合規(guī)定的,仍然使用網(wǎng)景公司草案定義的expires而不使用標準的max-age屬性服務器需要。這個參數(shù)期望得到一個java.util.Collection類型的值。集合元素必須是java.lang.String類型,來兼容java.text.SimpleDateFormat的語法。如果這個參數(shù)沒有被設置,那么默認的選擇就是CookieSpec實現(xiàn)規(guī)范的值。要注意這個參數(shù)的應用。
- 'http.protocol.single-cookie-header':定義了是否cookie應該強制到一個獨立的Cookie請求頭部信息中。否則,每個cookie就被當作分離的Cookie頭部信息來格式化。這個參數(shù)期望得到一個java.lang.Boolean類型的值。如果這個參數(shù)沒有被設置,那么默認的選擇就是CookieSpec實現(xiàn)規(guī)范的值。要注意這個參數(shù)僅僅嚴格應用于cookie規(guī)范(RFC 2109和RFC 2965)。瀏覽器兼容性和網(wǎng)景公司草案策略將會放置所有的cookie到一個請求頭部信息中。
- 'http.protocol.cookie-policy':定義了用于HTTP狀態(tài)管理的cookie規(guī)范的名字。這個參數(shù)期望得到一個java.lang.String類型的值。如果這個參數(shù)沒有被設置,那么合法的日期格式就是CookieSpec實現(xiàn)規(guī)范的值。
3.4 Cookie規(guī)范注冊表
- 兼容性:瀏覽器兼容性(寬松策略)。
- 網(wǎng)景:網(wǎng)景公司草案。
- rfc2109:RFC 2109(過時的嚴格策略)。
- rfc2965:RFC 2965(嚴格策略的標準符合)。
- best-match:最佳匹配meta(元)策略。
3.5 選擇cookie策略
HttpClient httpclient = new DefaultHttpClient();// 對每個默認的強制嚴格cookie策略httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2965);HttpGet httpget = new HttpGet("http://www.broken-server.com/");// 對這個請求覆蓋默認策略httpget.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
3.6 定制cookie策略
CookieSpecFactory csf = new CookieSpecFactory() {public CookieSpec newInstance(HttpParams params) {return new BrowserCompatSpec() {@Overridepublic void validate(Cookie cookie, CookieOrigin origin)throws MalformedCookieException {// 這相當簡單}};}};DefaultHttpClient httpclient = new DefaultHttpClient();httpclient.getCookieSpecs().register("easy", csf);httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, "easy");
3.7 Cookie持久化
DefaultHttpClient httpclient = new DefaultHttpClient();// 創(chuàng)建一個本地的cookie store實例CookieStore cookieStore = new MyCookieStore();// 如果需要填充cookieBasicClientCookie cookie = new BasicClientCookie("name", "value");cookie.setVersion(0);cookie.setDomain(".mycompany.com");cookie.setPath("/");cookieStore.addCookie(cookie);// 設置存儲httpclient.setCookieStore(cookieStore);
3.8 HTTP狀態(tài)管理和執(zhí)行上下文
- 'http.cookiespec-registry':CookieSpecRegistry實例代表了實際的cookie規(guī)范注冊表。這個屬性的值設置在本地內(nèi)容中,優(yōu)先于默認的。
- 'http.cookie-spec':CookieSpec實例代表真實的cookie規(guī)范。
- 'http.cookie-origin':CookieOrigin實例代表了真實的源服務器的詳細信息。
- 'http.cookie-store':CookieStore實例代表了真實的cookie存儲。設置在本地內(nèi)容中的這個屬性的值優(yōu)先于默認的。
本地的HttpContext對象可以被用來定制HTTP狀態(tài)管理內(nèi)容,先于請求執(zhí)行或在請求執(zhí)行之后檢查它的狀態(tài):
HttpClient httpclient = new DefaultHttpClient();HttpContext localContext = new BasicHttpContext();HttpGet httpget = new HttpGet("http://localhost:8080/");HttpResponse response = httpclient.execute(httpget, localContext);CookieOrigin cookieOrigin = (CookieOrigin) localContext.getAttribute(ClientContext.COOKIE_ORIGIN);System.out.println("Cookie origin: " + cookieOrigin);CookieSpec cookieSpec = (CookieSpec) localContext.getAttribute(ClientContext.COOKIE_SPEC);System.out.println("Cookie spec used: " + cookieSpec);
3.9 每個用戶/線程的狀態(tài)管理
HttpClient httpclient = new DefaultHttpClient();// 創(chuàng)建cookie store的本地實例CookieStore cookieStore = new BasicCookieStore();// 創(chuàng)建本地的HTTP內(nèi)容HttpContext localContext = new BasicHttpContext();// 綁定定制的cookie store到本地內(nèi)容中localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);HttpGet httpget = new HttpGet("http://www.google.com/");// 作為參數(shù)傳遞本地內(nèi)容HttpResponse response = httpclient.execute(httpget, localContext)
http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113246.html