Apache HttpClient : Http Cookies

前言

HttpClient已经被集成到Android的SDK里,但在JDK里面仍然需要HttpURLConnectionn发起HTTP请求。HttpClient可以看做是一个加强版的HttpURLConnection,但它的侧重点是如何发送请求、接受相应和管理Http连接。

在介绍Http Cookies之前,笔者给出一个应用场景:你需要一个根据地理信息(城市名或者经纬度)获取天气的应用。可选的API很多,不幸的是,网上提到的Google天气API已经停止服务了(不是被墙);雅虎是英文的,且需要得到其城市ID;其他各种知名或不知名的要么收费,要么不好用。实际上,百度推出的车联网API也支持天气服务,不过每个申请的AK原则上访问次数有限(真要做天气应用,推荐使用中国国家气象局的API)。当在百度你申请了AK,发出访问时,可能有这样的提示:

其基本代码如下:

CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpGet get = new HttpGet("http://api.map.baidu.com/telematics/v3/weather?location=西安&output=json&ak=yourkey");
		CloseableHttpResponse response = httpClient.execute(get);
		System.out.println(EntityUtils.toString(response.getEntity()));

其实,做个爬虫的朋友大多遇到这个警告:Cookie rejected。

好吧。Cookie rejected,下面我们详细讨论HttpClient的Cookie管理机制。

什么是Cookie

一个Http Cookie就是一个令牌或者状态信息的短包,用来在Http代理和目标服务器间维护一个session交互信息。这个名字最早来自于Netscape的工程师。

Httpclient使用Cookie的接口来表示抽象的cookie令牌。它最简单的形式是一个键值对。通常一个Http cookie也包含大量属性,比如版本号,合法的域,在原始服务器上的该cooki起作用的子集URL的路径,cookie存活的最大时间等。

SetCookie接口表示一个由服务器发给Http代理的Set-Cookie响应头,用以维护会话状态。SetCookie2接口继承了SetCookie,并有特定的Set-Cookie2方法。

ClientCookie接口继承了Cookie接口,并添加了额外的特殊功能,比如获取原始的Cookie属性。这对产生Cookie头很重要,因为一些cookie说明要求Cookie头包含只在Set-Cookie或Set-Cookie指定的特定属性。

Cookie版本号

与Netscape草案兼容但不和官方规范兼容的被看做是版本0,标准的兼容cookie被看做是版本1。HttpClient根据版本号可能会以不同方式处理cookie。

下面是一个标准cookie重建的例子。注意:标准兼容cookie必须保留所有来自原始服务器的属性。

BasicClientCookie2 stdCookie = new BasicClientCookie2("name", "value");
stdCookie.setVersion(1);
stdCookie.setDomain(".baidu.com");
stdCookie.setPorts(new int[] {80,8080});
stdCookie.setPath("/");
stdCookie.setSecure(true);
stdCookie.setAttribute(ClientCookie.VERSION_ATTR, "1");
stdCookie.setAttribute(ClientCookie.DOMAIN_ATTR, ".baidu.com");
stdCookie.setAttribute(ClientCookie.PORT_ATTR, "80,8080");

Cookie规范

CookieSpe接口表示一个Cookie管理规范。这个规范有:

  1. Set-Cookie的传递规则和可选的Set-Cookie2头信息
  2. 已传递cookie的验证
  3. 对所给主机、端口和路径的Cookie头的形式

下面有几种Cookie的实现:

Netscape draft:由Netscape委员会发布的原始草案。除非为了绝对的兼容,请避免使用。

Standard:RFC 2965 HTTP 状态管理规范。

Browser compatibility:该实现竭力减小常见浏览器的差异性。

Best match:“元”cookie规范,依据Http响应cookie的格式得到一个cookie规范。基本上集合了上面的所有。

Ignore cookies:忽略所有。

强烈建议使用Best match。

选择cookie 策略

cookie策略可以在Http客户端设置,并在必要时可在Http requset级别上重写。

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策略

为了实现一个定制的cookie策略,需要实现CookieSpec接口,创建一个CookieSpeProvier的实现来创建和初始化自定义规范并进行注册。一旦定制的规范完成了注册,它可以像标准的cookie规范一样被激活。

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();

Cookie的持久化

HttpClien可以和任何实现CookieStrore接口的持久化cookie store的物理表示协作。默认的CookieStroe实现是BasicCookie,它是用一个ArrayList实现的。不幸的是,当垃圾回收时存储在BasicClientCookie对象的数据会丢失。

// 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();

现在HttpClient里面的Cookie的问题基本介绍清楚了。我们使用标准的cookie策略,重新获取天气的代码。

RequestConfig globalConfig = RequestConfig.custom().
				setCookieSpec(CookieSpecs.BEST_MATCH).build();

        CloseableHttpClient client = HttpClients.custom().
        		setDefaultRequestConfig(globalConfig).build();

        RequestConfig localConfig = RequestConfig.copy(globalConfig)
                .setCookieSpec(CookieSpecs.BROWSER_COMPATIBILITY)
                .build();
        HttpGet get = new HttpGet(sb.toString());
        get.setConfig(localConfig);

		CloseableHttpResponse response = client.execute(get);

		String weatherDetail = EntityUtils.toString(response.getEntity());

返回结果:

Apache HttpClient : Http Cookies,布布扣,bubuko.com

时间: 2024-10-06 00:43:36

Apache HttpClient : Http Cookies的相关文章

android使用apache httpclient发送post请求

package com.liuc; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.ht

Apache HttpClient访问网络工具类

1 package com.ztravel.utils; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org

论httpclient上传带参数【commons-httpclient和apache httpclient区别】

需要做一个httpclient上传,然后啪啪啪网上找资料 1.首先以前系统中用到的了commons-httpclient上传,找了资料后一顿乱改,然后测试 PostMethod filePost = new PostMethod(url); filePost.setParameter("system", "vinuxpost"); try { Part part[] = UploadRequestHelper.getPart(request); filePost.s

新旧apache HttpClient 获取httpClient方法

在apache httpclient 4.3版本中对很多旧的类进行了deprecated标注,通常比较常用的就是下面两个类了. DefaultHttpClient -> CloseableHttpClientHttpResponse -> CloseableHttpResponse 目前互联网对外提供的接口通常都是HTTPS协议,有时候接口提供方所示用的证书会出现证书不受信任的提示,chrome访问接口(通常也不会用chrome去访问接口,只是举个例子)会出现这样的提示: 为此我们调用这类接口

使用Apache HttpClient 4.x发送Json数据

Apache HttpClient是Apache提供的一个开源组件,使用HttpClient可以很方便地进行Http请求的调用.自4.1版本开始,HttpClient的API发生了较大的改变,很多方法的调用方式已经和3.x版本不同.本文使用的是当前最新的4.5.3版本. 首先在pom文件中引入httpcomponents依赖包: 1 <dependency> 2 <groupId>org.apache.httpcomponents</groupId> 3 <art

Android 6.0 使用 Apache HttpClient

Android 6.0版本已经已经基本将Apahce Http Client 移除出SDK. 那么问题来了,如果我在以前的项目中使用了Apache HttpClient相关类,怎么办呢? 请看官网给出的答案 Apache HTTP Client Removal Android 6.0 release removes support for the Apache HTTP client. If your app is using this client and targets Android 2.

用Apache httpclient模拟登陆学生个人信息系统

不同学校的教务系统设计应该会有不同,这里就只针对我的学校.本文主要讲作为纯小白连返回码302都还不懂的我是怎么一步步整的. 我打算用的是java. 因为模拟登录这块以前都没做过,就简单百度了下,找到了开发用的相应的包,比如httpclient,网上也有别人做好的代码上传的,所以就先跑跑别人的代码试试呗,记住把需要的jar包先下好并导入到工程,下面是别人的代码 package com.zb.util; import java.io.BufferedReader; import java.io.In

apache httpclient和fileupload包使用

package httpclient; import java.awt.Image; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInputS

基于apache —HttpClient的小爬虫获取网页内容

今天(17-03-31)忙了一下午研究webmagic,发现自己还太年轻,对于这样难度的框架(类库) 还是难以接受,还是从基础开始吧,因为相对基础的东西教程相多一些,于是乎我找了apache其下的 HttpClient,根据前辈们发的教程自己也简单写了一下,感觉还好. 下面实现的是单个页面的获取: import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.clien