最初HTTP被设计为无状态的,面向请求/响应的协议,对于跨(spanning across)多个逻辑相关的请求/响应交换的有状态会话没有特别规定(provisions)。随着HTTP协议的普及和采用越来越多的系统开始将其用于应用程序,它从来不用于例如电子商务应用的传输。 因此,状态管理的支持成为必然。
Netscape Communications当时是网络客户端和服务器软件的领先开发商,它们基于专有规范(proprietary specification)实现了对其产品中的HTTP状态管理的支持。之后,Netscape试图通过发布规范草案来规范机制。这些努力有助于通过RFC标准轨道定义的正式规范。然而,大量应用程序中的状态管理仍然主要基于Netscape草案,与官方规范不兼容。 Web浏览器的所有主要开发人员都被迫保持与这些应用程序的兼容性,从而大大有助于标准兼容性的分散。
3.1. HTTP cookies
HTTP cookie是HTTP代理和目标服务器可以进行交换以维护会话的令牌或短的状态信息包。被Netscape的工程师称为“magic cookie”。
HttpClient使用Cookie接口来表示一个抽象的cookie令牌。在最简单的形式中,HTTP cookie只是一个名称/值对。 通常,HTTP cookie还包含许多属性,例如一个有效的域,一个指定该cookie适用的源服务器上的URL子集的路径以及cookie有效的最长时间段。
SetCookie接口表示由源服务器发送给HTTP代理的Set-Cookie响应头,以保持会话状态。
ClientCookie接口通过附加的客户端特定功能扩展了Cookie接口,例如与原始服务器指定的原始cookie属性完全相同的功能。 这对于生成Cookie标头很重要,因为一些Cookie规范要求Cookie标头只有在Set-Cookie标题中指定时才包含某些属性。
以下是创建客户端Cookie对象的示例:
BasicClientCookie cookie=new BasicClientCookie("name", "value");
//设置有效的domain和path属性
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
//或者使用以下的等价形式
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
3.2. Cookie 规范
CookieSpec
接口表示一个cookie的管理规范.内容如下:
-
解析
Set-Cookie
头部的规则. -
已解析的Cookie的验证规则。
-
格式化给定主机的Cookie标头,端口和起始路径。
HttpClient 附带了许多CookieSpec的实现
:
-
Standard strict: 状态管理策略符合由RFC 6265第4节定义的良好的配置文件的语法和语义。
-
Standard: .状态管理策略符合RFC 6265第4节定义的更宽松的配置文件,旨在与不符合标准配置(well behaved profile)的现有服务器协同工作(interoperability)。
-
Netscape draft (废弃): 此策略符合Netscape Communications发布的原始规范。 除非与传统代码的兼容性绝对必要,否则应该避免这种情况。
-
RFC 2965 (废弃): 此状态管理策略符合RFC 2965定义的废弃(obsolete )状态管理规范。请勿在新的应用程序中使用。
-
RFC 2109 (废弃): 此状态管理策略符合RFC 2109定义的过时状态管理规范。请勿在新的应用程序中使用。
-
Browser compatibility (obsolete): 此策略致力于密切模仿旧版本的浏览器应用程序(如Microsoft Internet Explorer和Mozilla FireFox)的(mis)行为。 请不要在新的应用程序中使用。
-
Default: 默认cookie策略是根据基于HTTP响应发送的cookie的属性(如版本属性,现在已过时)的RFC 2965,RFC 2109或Netscape草案兼容实现的合成策略。 此政策将不利于下一个次要版本的HttpClient中的标准(RFC 6265兼容)实现。
-
Ignore cookies: 所有的cookies 将会被忽略.
强烈建议在新应用程序中使用标准或标准严格策略。 只能使用过时的规格与旧系统兼容。 支持过时的规范将在下一个主要版本的HttpClient中被删除。
3.3. 设置 cookie 规范
可以在HTTP客户端设置Cookie策略,如果需要,可以在HTTP请求级别覆盖Cookie策略。(我本地的版本是4.3的估计4.5的对于Cookie规范有新的更改,增加了
CookieSpecs.DEFAULTCookieSpecs.STANDARD_STRICT
RequestConfig globalConfig=RequestConfig.custom()
.setCookieSpec(CookieSpecs.STANDARD)
.build();
CloseableHttpClient client=HttpClients.custom()
.setDefaultRequestConfig(globalConfig)
.build();
RequestConfig localConfig=RequestConfig.copy(globalConfig)
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
HttpGet get=new HttpGet("/");
get.setConfig(localConfig);
3.4. 自定义cookie规范
为了实现自定义cookie规范,应该创建一个自定义的CookieSpec接口实现,创建一个CookieSpecProvider实现来创建和初始化自定义规范的实例并使用HttpClient注册工厂。 一旦定制规范被注册,它可以与标准cookie规范一样使用。
PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>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存储的任何物理表示。 名为BasicCookieStore的默认CookieStore实现是由java.util.ArrayList支持的简单实现。 存储在BasicClientCookie对象中的Cookie将在容器对象收集垃圾时丢失。 如果需要,用户可以提供更复杂的实现。
BasicClientCookie cookie=new BasicClientCookie("name", "value");
//设置有效的domain和path属性
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
//或者使用以下的等价形式
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
//创建一个本地的cookie store实例
CookieStore cookieStore=new BasicCookieStore();
cookieStore.addCookie(cookie);
//设置cookieStore
CloseableHttpClient client=HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.build();
3.6. HTTP 状态管理和 执行上下文
在HTTP请求执行过程中,HttpClient将以下状态管理相关对象添加到执行上下文中:
-
Lookup
:代表实际的cookie规范注册表的实例。 在本地上下文中设置的此属性的值优先于默认值。 -
CookieSpec
:代表实际的cookie规范. -
CookieOrigin:
代表原始服务器的实际细节的实例. -
CookieStore
:代表实际的cookie存储的实例。 在本地上下文中设置的此属性的值优先于默认值.
BasicClientCookie cookie=new BasicClientCookie("name", "value");
//设置有效的domain和path属性
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
//或者使用以下的等价形式
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
cookie.setAttribute(ClientCookie.PATH_ATTR, "/");
//创建一个本地的cookie store实例
CookieStore cookieStore=new BasicCookieStore();
cookieStore.addCookie(cookie);
//设置cookieStore
CloseableHttpClient client=HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.build();
Lookup<CookieSpecProvider> cookieSpecReg =RegistryBuilder.<CookieSpecProvider>create()
.build();
HttpClientContext context = HttpClientContext.create();
context.setCookieSpecRegistry(cookieSpecReg);
context.setCookieStore(cookieStore);
HttpGet get=new HttpGet("/");
CloseableHttpResponse response1 = client.execute(get, context);
// Cookie origin details
CookieOrigin cookieOrigin = context.getCookieOrigin();
// Cookie spec used
CookieSpec cookieSpec = context.getCookieSpec();