HttpClient 4.3详细教程之Http状态管理
2017-07-14 15:06
746 查看
最初,Http被设计成一个无状态的,面向请求/响应的协议,所以它不能在逻辑相关的http请求/响应中保持状态会话。由于越来越多的系统使用http协议,其中包括http从来没有想支持的系统,比如电子商务系统。因此,http支持状态管理就很必要了。
当时的web客户端和服务器软件领先者,网景(netscape)公司,最先在他们的产品中支持http状态管理,并且制定了一些专有规范。后来,网景通过发规范草案,规范了这一机制。这些努力促成 RFC standard track制定了标准的规范。但是,现在多数的应用的状态管理机制都在使用网景公司的规范,而网景的规范和官方规定是不兼容的。因此所有的浏览器开发这都被迫兼容这两种协议,从而导致协议的不统一。
所谓的Http cookie就是一个token或者很短的报文信息,http代理和服务器可以通过cookie来维持会话状态。网景的工程师把它们称作“magic cookie”。
HttpClient使用
兼容网景的规范,但是不兼容官方规范的cookie,是版本0. 兼容官方规范的版本,将会是版本1。版本1中的Cookie可能和版本0工作机制有差异。
下面的代码,创建了网景版本的Cookie:
[java] view
plaincopy
BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");
netscapeCookie.setVersion(0);
netscapeCookie.setDomain(".mycompany.com");
netscapeCookie.setPath("/");
下面的代码,创建标准版本的Cookie。注意,标准版本的Cookie必须保留服务器发送过来的Cookie所有属性。
[java] view
plaincopy
BasicClientCookie stdCookie = new BasicClientCookie("name", "value");
stdCookie.setVersion(1);
stdCookie.setDomain(".mycompany.com");
stdCookie.setPath("/");
stdCookie.setSecure(true);
// Set attributes EXACTLY as sent by the server
stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
下面的代码,创建了
[java] view
plaincopy
BasicClientCookie2 stdCookie = new
182e9
BasicClientCookie2("name", "value");
stdCookie.setVersion(1);
stdCookie.setDomain(".mycompany.com");
stdCookie.setPorts(new int[] {80,8080});
stdCookie.setPath("/");
stdCookie.setSecure(true);
// Set attributes EXACTLY as sent by the server
stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
解析
验证Cookie的规则
将指定的主机名、端口和路径格式化成Cookie头消息
HttpClient有下面几种
Netscape draft: 这种符合网景公司指定的规范。但是尽量不要使用,除非一定要保证兼容很旧的代码。
Standard: RFC 2965 HTTP状态管理规范
Browser compatibility: 这种方式,尽量模仿常用的浏览器,如IE和firefox
Best match: ‘Meta’ cookie specification that picks up a cookie policy based on the format of cookies sent with
the HTTP response.它基本上将上面的几种规范积聚到一个类中。
++ Ignore cookies: 忽略所有Cookie
强烈推荐使用Best Match匹配规则,让HttpClient根据运行时环境自己选择合适的规范。
我们可以在创建Http client的时候指定Cookie测试,如果需要,也可以在执行http请求的时候,进行覆盖指定。
[java] view
plaincopy
RequestConfig globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultRequestConfig(globalConfig)
.build();
RequestConfig localConfig = RequestConfig.copy(globalConfig)
.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
.build();
HttpGet httpGet = new HttpGet("/");
httpGet.setConfig(localConfig);
如果我们要自定义Cookie测试,就要自己实现
[java] view
plaincopy
CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
public CookieSpec create(HttpContext context) {
return new BrowserCompatSpec() {
@Override
public void validate(Cookie cookie, CookieOrigin origin)
throws MalformedCookieException {
// Oh, I am easy
}
};
}
};
Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.BEST_MATCH,
new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY,
new BrowserCompatSpecFactory())
.register("easy", easySpecProvider)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec("easy")
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(requestConfig)
.build();
HttpClient可以使用任何存储方式的cookie store,只要这个cookie store实现了
[java] view
plaincopy
// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Populate cookies if needed
BasicClientCookie cookie = new BasicClientCookie("name", "value");
cookie.setVersion(0);
cookie.setDomain(".mycompany.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);
// Set the store
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.build();
在Http请求执行过程中,HttpClient会自动向执行上下文中添加下面的状态管理对象:
本地的
store会覆盖在http Client层级的默认值。
[java] view
plaincopy
CloseableHttpClient httpclient = <...>
Lookup<CookieSpecProvider> 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();
当时的web客户端和服务器软件领先者,网景(netscape)公司,最先在他们的产品中支持http状态管理,并且制定了一些专有规范。后来,网景通过发规范草案,规范了这一机制。这些努力促成 RFC standard track制定了标准的规范。但是,现在多数的应用的状态管理机制都在使用网景公司的规范,而网景的规范和官方规定是不兼容的。因此所有的浏览器开发这都被迫兼容这两种协议,从而导致协议的不统一。
3.1. Http cookies
所谓的Http cookie就是一个token或者很短的报文信息,http代理和服务器可以通过cookie来维持会话状态。网景的工程师把它们称作“magic cookie”。HttpClient使用
Cookie接口来代表cookie。简单说来,cookie就是一个键值对。一般,cookie也会包含版本号、域名、路径和cookie有效期。
SetCookie接口可以代表服务器发给http代理的一个set-cookie响应头,在浏览器中,这个set-cookie响应头可以写入cookie,以便保持会话状态。
SetCookie2接口对
SetCookie接口进行了拓展,添加了
Set-Cookie2方法。
ClientCookie接口继承了
Cookie接口,并进行了功能拓展,比如它可以取出服务器发送过来的原始cookie的值。生成头消息是很重要的,因为只有当cookie被指定为
Set-Cookie或者
Set-Cookie2时,它才需要包括一些特定的属性。
3.1.1 COOKIES版本
兼容网景的规范,但是不兼容官方规范的cookie,是版本0. 兼容官方规范的版本,将会是版本1。版本1中的Cookie可能和版本0工作机制有差异。下面的代码,创建了网景版本的Cookie:
[java] view
plaincopy
BasicClientCookie netscapeCookie = new BasicClientCookie("name", "value");
netscapeCookie.setVersion(0);
netscapeCookie.setDomain(".mycompany.com");
netscapeCookie.setPath("/");
下面的代码,创建标准版本的Cookie。注意,标准版本的Cookie必须保留服务器发送过来的Cookie所有属性。
[java] view
plaincopy
BasicClientCookie stdCookie = new BasicClientCookie("name", "value");
stdCookie.setVersion(1);
stdCookie.setDomain(".mycompany.com");
stdCookie.setPath("/");
stdCookie.setSecure(true);
// Set attributes EXACTLY as sent by the server
stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
下面的代码,创建了
Set-Cookie2兼容cookie。
[java] view
plaincopy
BasicClientCookie2 stdCookie = new
182e9
BasicClientCookie2("name", "value");
stdCookie.setVersion(1);
stdCookie.setDomain(".mycompany.com");
stdCookie.setPorts(new int[] {80,8080});
stdCookie.setPath("/");
stdCookie.setSecure(true);
// Set attributes EXACTLY as sent by the server
stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".mycompany.com");
stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
3.2. Cookie规范
CookieSpec接口代表了Cookie管理规范。Cookie管理规范规定了:
解析
Set-Cookie和
Set-Cookie2(可选)头消息的规则
验证Cookie的规则
将指定的主机名、端口和路径格式化成Cookie头消息
HttpClient有下面几种
CookieSpec规范:
Netscape draft: 这种符合网景公司指定的规范。但是尽量不要使用,除非一定要保证兼容很旧的代码。
Standard: RFC 2965 HTTP状态管理规范
Browser compatibility: 这种方式,尽量模仿常用的浏览器,如IE和firefox
Best match: ‘Meta’ cookie specification that picks up a cookie policy based on the format of cookies sent with
the HTTP response.它基本上将上面的几种规范积聚到一个类中。
++ Ignore cookies: 忽略所有Cookie
强烈推荐使用Best Match匹配规则,让HttpClient根据运行时环境自己选择合适的规范。
3.3. 选择Cookie策略
我们可以在创建Http client的时候指定Cookie测试,如果需要,也可以在执行http请求的时候,进行覆盖指定。[java] view
plaincopy
RequestConfig globalConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.BEST_MATCH)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultRequestConfig(globalConfig)
.build();
RequestConfig localConfig = RequestConfig.copy(globalConfig)
.setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
.build();
HttpGet httpGet = new HttpGet("/");
httpGet.setConfig(localConfig);
3.4. 自定义Cookie策略
如果我们要自定义Cookie测试,就要自己实现CookieSpec接口,然后创建一个
CookieSpecProvider接口来新建、初始化自定义
CookieSpec接口,最后把
CookieSpecProvider注册到HttpClient中。一旦我们注册了自定义策略,就可以像其他标准策略一样使用了。
[java] view
plaincopy
CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
public CookieSpec create(HttpContext context) {
return new BrowserCompatSpec() {
@Override
public void validate(Cookie cookie, CookieOrigin origin)
throws MalformedCookieException {
// Oh, I am easy
}
};
}
};
Registry<CookieSpecProvider> r = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.BEST_MATCH,
new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY,
new BrowserCompatSpecFactory())
.register("easy", easySpecProvider)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec("easy")
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(requestConfig)
.build();
3.5. Cookie持久化
HttpClient可以使用任何存储方式的cookie store,只要这个cookie store实现了CookieStore接口。默认的CookieStore通过
java.util.ArrayList简单实现了
BasicCookieStore。存在在
BasicCookieStore中的Cookie,当载体对象被当做垃圾回收掉后,就会丢失。如果必要,用户可以自己实现更为复杂的方式。
[java] view
plaincopy
// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Populate cookies if needed
BasicClientCookie cookie = new BasicClientCookie("name", "value");
cookie.setVersion(0);
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对象 代表实际的cookie规范registry。在当前上下文中的这个值优先于默认值。
CookieSpec对象 代表实际的Cookie规范。
CookieOrigin对象 代表实际的origin server的详细信息。
CookieStore对象 表示Cookie store。这个属性集中的值会取代默认值。
本地的
HttpContext对象可以用来在Http请求执行前,自定义Http状态管理上下文;或者测试http请求执行完毕后上下文的状态。我们也可以在不同的线程中使用不同的执行上下文。我们在http请求层指定的cookie规范集和cookie
store会覆盖在http Client层级的默认值。
[java] view
plaincopy
CloseableHttpClient httpclient = <...>
Lookup<CookieSpecProvider> 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();
相关文章推荐
- HttpClient 4.3详细教程之连接管理
- HttpClient 4.3详细教程之HTTP认证
- HttpClient 4.3详细教程之快速API
- HttpClient 中文官方教程----第3章HTTP状态管理-只收录,未测试
- HttpClient 4.3详细教程之基本概念
- HttpClient 4.3详细教程之HTTP缓存
- HttpClient 4.3详细教程
- HttpClient 4.3详细教程之高级主题
- HttpClient 4.3详细教程
- HttpClient 教程3 (HTTP状态管理)
- HttpClient 4.3详细教程
- HttpClient 4.3详细教程
- HttpClient 4.3详细教程
- Part2-HttpClient官方教程-Chapter3-HTTP状态管理
- HttpClient 4.3教程 第一章 基本概念
- HttpClient4.5教程-第三章-HTTP状态管理
- HttpClient 4.3教程 第一章 基本概念
- HttpClient 4.3教程-前言
- httpclient 4.3教程第一章 基本概念
- HttpClient 4.3教程