ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# httpclient3 <div><div style="font-family:Verdana, Arial, Tahoma, sans-serif;font-size:large;font-weight:bold;"><span style="font-size:19px;">第三章 HTTP状态管理</span></div><div style="font-family:Verdana, Arial, Tahoma, sans-serif;font-size:9.5pt;"><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">原 始的HTTP是被设计为无状态的,面向请求/响应的协议,没有特殊规定有状态的,贯穿一些逻辑相关的请求/响应交换的会话。由于HTTP协议变得越来越普 及和受欢迎,越来越多的从前没有打算使用它的系统也开始为应用程序来使用它,比如作为电子商务应用程序的传输方式。因此,支持状态管理就变得非常必要了。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">网 景公司,一度成为Web客户端和服务器软件开发者的领导方向,在它们基于专有规范的产品中实现了对HTTP状态管理的支持。之后,网景公司试图通过发布规 范草案来规范这种机制。它们的努力通过RFC标准跟踪促成了这些规范定义。然而,在很多应用程序中的状态管理仍然基于网景公司的草案而不兼容官方的规范。 很多主要的Web浏览器开发者觉得有必要保留那些极大促进标准片段应用程序的兼容性。</p><h3>3.1 HTTP cookies</h3><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Cookie是HTTP代理和目标服务器可以交流保持会话的状态信息的令牌或短包。网景公司的工程师用它来指“魔法小甜饼”和粘住的名字。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient 使用Cookie接口来代表抽象的cookie令牌。在它的简单形式中HTTP的cookie几乎是名/值对。通常一个HTTP的cookie也包含一些 属性,比如版本号,合法的域名,指定cookie应用所在的源服务器URL子集的路径,cookie的最长有效时间。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SetCookie接口代表由源服务器发送给HTTP代理的响应中的头部信息Set-Cookie来维持一个对话状态。SetCookie2接口和指定的Set-Cookie2方法扩展了SetCookie。</p><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">SetCookie 接口和额外的如获取原始cookie属性的能力,就像它们由源服务器指定的客户端特定功能扩展了Cookie接口。这对生成Cookie头部很重要,因为 一些cookie规范需要。Cookie头部应该包含在Set-Cookie或Set-Cookie2头部中指定的特定属性。</p><h4>3.1.1 Cookie版本</h4><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Cookie兼容网景公司的草案标准,但是版本0被认为是不符合官方规范的。符合标准的cookie的期望版本是1。HttpClient可以处理基于不同版本的cookie。</div><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">这里有一个重新创建网景公司草案cookie示例:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">netscapeCookie.setVersion(0);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">netscapeCookie.setDomain(".mycompany.com");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">netscapeCookie.setPath("/");</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">这是一个重新创建标准cookie的示例。要注意符合标准的cookie必须保留由源服务器发送的所有属性:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicClientCookie stdCookie = new BasicClientCookie("name", "value");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setVersion(1);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setDomain(".mycompany.com");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setPath("/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setSecure(true);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 精确设置由服务器发送的属性</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");</div></blockquote><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">这是一个重新创建Set-Cookie2兼容cookie的实例。要注意符合标准的cookie必须保留由源服务器发送的所有属性:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setVersion(1);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setDomain(".mycompany.com");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setPorts(new int[] {80,8080});</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setPath("/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setSecure(true);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 精确设置由服务器发送的属性</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");</div></blockquote><h3>3.2 Cookie规范</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieSpec接口代表了cookie管理的规范。Cookie管理规范希望如下几点:</div><ul><li><span style="color:#888888;">解析的Set-Cookie规则还有可选的Set-Cookie2头部信息。</span></li><li><span style="color:#888888;">验证解析cookie的规则。</span></li><li><span style="color:#888888;">格式化给定主机的Cookie头部信息,原始端口和路径。</span></li></ul><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient附带了一些CookieSpec的实现:</p><ul><li><span style="color:#888888;">网景公司草案:这个规范符合由网景通讯发布的原始草案规范。应当避免,除非有绝对的必要去兼容遗留代码。</span></li><li><span style="color:#888888;">RFC 2109:官方HTTP状态管理规范并取代的老版本,被RFC 2965取代。</span></li><li><span style="color:#888888;">RFC 2965:官方HTTP状态管理规范。</span></li><li><span style="color:#888888;">浏览器兼容性:这个实现努力去密切模仿(mis)通用Web浏览器应用程序的实现。比如微软的Internet Explorer和Mozilla的FireFox浏览器。</span></li><li><span style="color:#888888;">最佳匹配:’Meta’(元)cookie规范采用了一些基于又HTTP响应发送的cookie格式的cookie策略。它基本上聚合了以上所有的实现到以一个类中。</span></li></ul><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">强烈建议使用Best Match策略,让HttpClient在运行时基于执行上下文采用一些合适的兼容等级。</div><h3>3.3 HTTP cookie和状态管理参数</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">这些是用于定制HTTP状态管理和独立的cookie规范行为的参数。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><ul><li><span style="color:#888888;">'http.protocol.cookie- datepatterns':定义了用于解析非标准的expires属性的合法日期格式。只是对兼容不符合规定的,仍然使用网景公司草案定义的 expires而不使用标准的max-age属性服务器需要。这个参数期望得到一个java.util.Collection类型的值。集合元素必须是 java.lang.String类型,来兼容java.text.SimpleDateFormat的语法。如果这个参数没有被设置,那么默认的选择就 是CookieSpec实现规范的值。要注意这个参数的应用。</span></li><li><span style="color:#888888;">'http.protocol.single- cookie-header':定义了是否cookie应该强制到一个独立的Cookie请求头部信息中。否则,每个cookie就被当作分离的 Cookie头部信息来格式化。这个参数期望得到一个java.lang.Boolean类型的值。如果这个参数没有被设置,那么默认的选择就是 CookieSpec实现规范的值。要注意这个参数仅仅严格应用于cookie规范(RFC 2109和RFC 2965)。浏览器兼容性和网景公司草案策略将会放置所有的cookie到一个请求头部信息中。</span></li><li><span style="color:#888888;">'http.protocol.cookie-policy':定义了用于HTTP状态管理的cookie规范的名字。这个参数期望得到一个java.lang.String类型的值。如果这个参数没有被设置,那么合法的日期格式就是CookieSpec实现规范的值。</span></li></ul><h3>3.4 Cookie规范注册表</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient使用CookieSpecRegistry类维护一个可用的cookie规范注册表。下面的规范对于每个默认都是注册过的:</div><ul><li><span style="color:#888888;">兼容性:浏览器兼容性(宽松策略)。</span></li><li><span style="color:#888888;">网景:网景公司草案。</span></li><li><span style="color:#888888;">rfc2109:RFC 2109(过时的严格策略)。</span></li><li><span style="color:#888888;">rfc2965:RFC 2965(严格策略的标准符合)。</span></li><li><span style="color:#888888;">best-match:最佳匹配meta(元)策略。</span></li></ul><h3>3.5 选择cookie策略</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">Cookie策略可以在HTTP客户端被设置,如果需要,在HTTP请求级重写。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 对每个默认的强制严格cookie策略</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getParams().setParameter(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2965);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet("http://www.broken-server.com/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 对这个请求覆盖默认策略</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpget.getParams().setParameter(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);</div></blockquote><h3>3.6 定制cookie策略</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">为 了实现定制cookie策略,我们应该创建CookieSpec接口的定制实现类,创建一个CookieSpecFactory实现来创建和初始化定制实 现的实例并和HttpClient注册这个工厂。一旦定制实现被注册了,它可以和标准的cookie实现有相同的活性。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieSpecFactory csf = new CookieSpecFactory() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public CookieSpec newInstance(HttpParams params) {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">return new BrowserCompatSpec() {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">@Override</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">public void validate(Cookie cookie, CookieOrigin origin)</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">throws MalformedCookieException {</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 这相当简单</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">};</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">}</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">};</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getCookieSpecs().register("easy", csf);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.getParams().setParameter(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientPNames.COOKIE_POLICY, "easy");</div></blockquote><h3>3.7 Cookie持久化</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient 可以和任意物理表示的实现了CookieStore接口的持久化cookie存储一起使用。默认的CookieStore实现称为 BasicClientCookie,这是凭借java.util.ArrayList的一个简单实现。在BasicClientCookie对象中存储 的cookie当容器对象被垃圾回收机制回收时会丢失。如果需要,用户可以提供更复杂的实现。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">DefaultHttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 创建一个本地的cookie store实例</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieStore cookieStore = new MyCookieStore();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 如果需要填充cookie</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">BasicClientCookie cookie = new BasicClientCookie("name", "value");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">cookie.setVersion(0);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">cookie.setDomain(".mycompany.com");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">cookie.setPath("/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">cookieStore.addCookie(cookie);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 设置存储</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">httpclient.setCookieStore(cookieStore);</div></blockquote><h3>3.8 HTTP状态管理和执行上下文</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">在HTTP请求执行的过程中,HttpClient添加了下列和状态管理相关的对象到执行上下文中:</div><ul><li><span style="color:#888888;">'http.cookiespec-registry':CookieSpecRegistry实例代表了实际的cookie规范注册表。这个属性的值设置在本地内容中,优先于默认的。</span></li><li><span style="color:#888888;">'http.cookie-spec':CookieSpec实例代表真实的cookie规范。</span></li><li><span style="color:#888888;">'http.cookie-origin':CookieOrigin实例代表了真实的源服务器的详细信息。</span></li><li><span style="color:#888888;">'http.cookie-store':CookieStore实例代表了真实的cookie存储。设置在本地内容中的这个属性的值优先于默认的。</span></li></ul><p style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">本地的HttpContext对象可以被用来定制HTTP状态管理内容,先于请求执行或在请求执行之后检查它的状态:</p><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpContext localContext = new BasicHttpContext();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet("http://localhost:8080/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = httpclient.execute(httpget, localContext);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieOrigin cookieOrigin = (CookieOrigin) localContext.getAttribute(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientContext.COOKIE_ORIGIN);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println("Cookie origin: " + cookieOrigin);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieSpec cookieSpec = (CookieSpec) localContext.getAttribute(</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">ClientContext.COOKIE_SPEC);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">System.out.println("Cookie spec used: " + cookieSpec);</div></blockquote><h3>3.9 每个用户/线程的状态管理</h3><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">我们可以使用独立的本地执行上下文来实现对每个用户(或每个线程)状态的管理。定义在本地内容中的cookie规范注册表和cookie存储将会优先于设置在HTTP客户端级别中默认的那些。</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;"><blockquote style="background-color:#F9F9FF;"><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpClient httpclient = new DefaultHttpClient();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 创建cookie store的本地实例</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">CookieStore cookieStore = new BasicCookieStore();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 创建本地的HTTP内容</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpContext localContext = new BasicHttpContext();</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 绑定定制的cookie store到本地内容中</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpGet httpget = new HttpGet("http://www.google.com/");</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">// 作为参数传递本地内容</div><div style="color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;">HttpResponse response = httpclient.execute(httpget, localContext)</div></blockquote></div></div></div></div></div></div></div> > 资源参考 http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2112804.html