Java:HttpClient篇,Cookie概述,及其在HttpClient4.2中的应用
1. Cookie 概述
Cookie是什么? Cookie 是一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息。
为什么需要Cookie? 因为HTTP协议是无状态的,对于一个浏览器发出的多次请求,WEB服务器无法区分 是不是来源于同一个浏览器。所以,需要额外的数据用于维护会话。 Cookie 正是这样的一段随HTTP请求一起被传递的额外数据。
Cookie能做什么? Cookie只是一段文本,所以它只能保存字符串。而且浏览器对它有大小限制以及 它会随着每次请求被发送到服务器,所以应该保证它不要太大。 Cookie的内容也是明文保存的,有些浏览器提供界面修改,所以, 不适合保存重要的或者涉及隐私的内容。
Cookie 的限制。 大多数浏览器支持最大为 4096 字节的 Cookie。由于这限制了 Cookie 的大小,最好用 Cookie 来存储少量数据,或者存储用户 ID 之类的标识符。用户 ID 随后便可用于标识用户,以及从数据库或其他数据源中读取用户信息。 浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie;如果试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制,通常为 300 个。
2. HttpClient4.2支持的Cookie策略
Netscape标准
Netscape是最原始的Cookies规范,同时也是RFC2109的基础。尽管如此,还是在很多重要的方面与RFC2109不同,可能需要特定服务器才可以兼容。
RFC2109
RFC2109是W3C组织第一次推出的官方Cookies标准。理论上,所有使用版本1Cookies的服务端都应该使用此标准。HttpClient已经将此标准设定为默认。
遗憾的是,许多服务端不正确的实现了标准或者仍然使用Netscape标准。所有有时感到此标准太多于严格。
RFC2965
RFC2965定义了版本2并且尝试去弥补在版本1中Cookie的RFC2109标准的缺点。RFC2965是,并规定RFC2965最终取代RFC2109.
发送RFC2965标准Cookies的服务端,将会使用Set-Cookie2 header添加到Set-Cookie Header信心中,RFC2965 Cookies是区分端口的。
Browser Compatibility
这种兼容性设计要求是适应尽可能多的不同的服务器,尽管不是完全按照标准来实现的。如果你遇到了解析Cookies的问题,你就可能要用到这一个规范。
有太多的web站点是用CGI脚本去实现的,而导致只有将所有的Cookies都放入Request header才可以正常的工作。这种情况下最好设置http.protocol.single-cookie-header参数为true。
Best match
'Meta' cookie specification that picks up a cookie policy based on the format of cookies sent with the HTTP response. It basically aggregates all above implementations into one class.
Ignore Cookies
此规格忽略所有Cookie 。被用来防止HttpClient接受和发送的Cookie。
强烈建议使用Best match策略让HttpClient根据执行环境选择一个合适级别的策略。选择Cookie策略示范代码:
import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.params.CookiePolicy;
HttpClient httpclient = new DefaultHttpClient(); // force strict cookie policy per default httpclient.getParams().setParameter( ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2965); HttpGet httpget = new HttpGet("http://www.broken-server.com/"); // Override the default policy for this request httpget.getParams().setParameter( ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
3. HttpClient登录服务器后Cookie读取不全,通过IE浏览器登录则可以的问题
解决:
正常情况是因为HttpClient没有打开与IE相同的页面导致的。即IE曾经打开了哪些页面(通常是登录页面,也可能是会员页面等),HttpClient也必须打开同样的页面,否则它的Cookie就可能不全。最好是通过Fidder观察在浏览器中的操作与通过HttpClient操作有何差别,找出差别,然后予以解决。
Fiddler的使用参考:Fiddler教程(转);
在代码中设置代理服务器,参考:HttpClient4.2在Java中的几则应用:Get、Post参数、Session(会话)保持、Proxy(代理服务器)设置,多线程设置...
了解HTTP一些基础知识,参考:HTTP协议概述
通过Fiddler不仅可以解决上述问题,其实只要是IE浏览器能够做的事情,HttpClient如果做不了,那么就通过Fiddler来分析所有通讯数据,找出它们的差别,然后予以解决。
示范(自定义Cookie):
private HttpClient m_httpClient = new DefaultHttpClient();
private boolean login2Site() throws Exception { // 代码略 }
// 抓取页面 private String getHTMLPage(String url) throws Exception { String result = "";
HttpGet httpget = new HttpGet(url); httpget.setHeader("Referer", "http://www.yoursite.com/"); httpget.setHeader("Cookie", getCookies()); HttpResponse response = m_httpClient.execute(httpget); HttpEntity entity = response.getEntity(); result = EntityUtils.toString(entity, "GBK"); httpget.releaseConnection();
return result; } private String getCookies() { StringBuilder sb = new StringBuilder(); List<Cookie> cookies = ((AbstractHttpClient)m_httpClient).getCookieStore().getCookies(); for(Cookie cookie: cookies) sb.append(cookie.getName() + "=" + cookie.getValue() + ";"); // 除了HttpClient自带的Cookie,自己还可以增加自定义的Cookie // 增加代码...
return sb.toString(); }
功能强大的Fiddler
本文参考:
http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html
http://blog.csdn.net/ronghua_liu/article/details/8105463
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/statemgmt.html