13 关于HttpClient自动保存Cookie

来源:互联网 发布:安阳日报社 网络投稿 编辑:程序博客网 时间:2024/05/22 01:58

前言

下面是我以前想做的一个专门为了HXBlog “刷访问” 的工具,, 当时 直接使用的我的HXCrawler进行发送请求, 但是 很遗憾失败了,,

也就是 虽然我发送了”requestTime”个请求, 但是 该博客的”访问次数”依然仅仅增加了一次

因为 不知道为何发送第一个请求之后, 后面的所有请求都带上了第一次请求所得到的sessionId, 但是 问题在于, 我这里是每一次 都新建了一个CrawlerConfig啊, 因此 每次发送的请求应该都没有什么关系啊, 为什么 会出现这种情况呢,,

然后 今天上午花了一上午的时间[9月4日],来探索这个问题…

不过 好在有所收获, 请往下看 ↓

示例代码片


/** * file name : Test23PostRequestsForHXBlog.java * created at : 上午10:51:05 2016年8月6日 * created by 970655147 */package com.hx.test;public class Test23PostRequestsForHXBlog {   // 给HXBlog发送请求[刷数据]   public static void main(String[] args) throws Exception {//    String requestUrl = "http://localhost:8080/HXBlog/action/blogGetAction?blogId=38&tag=all";      String requestUrl = "http://localhost:8088/HXBlog/action/blogGetAction?blogId=16&tag=all";      int requestTime = 20;      flushVisit(requestUrl, requestTime);   }   // 给给定的url刷页面   // 真是不明白 为何刷不起呢?? 我的每一次请求都没有带东西啊, 但是debug服务端, 却又发现了sessoin, 以及cookie, 搞不懂,,   // 那么 这样看来刷赞估计也会gg掉了,,   public static void flushVisit(String requestUrl, int requestTime) throws Exception {      Crawler crawler = HtmlCrawler.getInstance();      for(int i=0; i<requestTime; i++) {//          CrawlerConfig config = HtmlCrawlerConfig.get();//          // config.addHeader(Tools.USER_AGENT, "abc");//              config.setTimeout(30 * 1000);//              config.addCookie("key", "val");//             Page page = crawler.getPage(requestUrl, config );//          String content = page.getContent();         // -------------------------------------------------------------------------------         String content = Request.Get(requestUrl).execute().returnContent().asString();          // -------------------------------------------------------------------------------         // 擦 果然是httpClient在作怪         // 可是 这是为何呢?                 --2016.09.04        // 卧槽 历经一个小时的debug终于找到问题之所在了,, 但是 httpClient为什么要缓存cookie呢??[估计是为了 减轻服务端的负载吧, 以及方便用户吧[从此不用在维护cookie了..] ]//       URL url = new URL(requestUrl);//       URLConnection con = url.openConnection();//       String content = Tools.getContent(con.getInputStream() );        Log.log(JSONObject.fromObject(content).getJSONObject("blog").getString("visited") );//          Tools.sleep(1000);      }   }}

“/action/blogGetAction” 这个action是获取对应的播客的信息的action, 其业务中会校验当前用户是否看过当前播客, 如果当前用户没有看过当前播客, 那么 当前播客的”访问次数” + 1

可以看到这里我有三次尝试[使用”—–”分割],

第一次是 直接使用HXCrawler进行发送请求, 然后 当时就出现了这个怪问题,, 百思不得其解, 因此 后来便放弃了
第二次是 今天上午我使用HttpClient的相关API直接发送请求, 我怀疑是否是我的HXCrawler在哪里封装存在问题, 但是 结果这个问题依然存在
第三次是 我开始怀疑是否是HttpClient在帮我做了某些事情,, 因此 使用原生的java相关API发送请求, 结果 “刷访问” 居然生效了,,

好了, 开始此次”旅行”吧, 一下内容中删去了一些我探索过程中碰到的”牛角尖”[花时间的但是无用的部分]

我这里环境为 : win7 + jdk1.7.40 + httpClient4.5

1. 首先 我怀疑是否是tomcat帮我做了一些事情

因此 我截取了一下服务器获取到的header, 下面的是第一次发送请求的header 和第二次发送请求的header


=== MimeHeaders ===

host = localhost:8088

connection = Keep-Alive

user-agent = Apache-HttpClient/4.5 (Java/1.7.0_40)

accept-encoding = gzip,deflate


=== MimeHeaders ===

host = localhost:8088

connection = Keep-Alive

user-agent = Apache-HttpClient/4.5 (Java/1.7.0_40)

cookie = JSESSIONID=5E6E98A6635B8CFFE609165763C05C73; isVisited_16=visited

accept-encoding = gzip,deflate


看到了吧, 原来客户端发送请求的时候 就多了一个cookie头, 里面有两个cookie, 一个是ssessionId, 另外一个是HXBlog中创建的Cookie

然后 我就想啊, 在第一二次尝试中, 我都没有特别的配置”Request.Get”获取到的请求啊, 为什么会增加了一个cookie头呢

2. 然后 我开始怀疑是否是HttpClient帮我做了些什么

然后 下载相关源码, 走一走这个流程, … 省略一个小时

ProtocolExec.execute
这里写图片描述

然后 问题出来了, 在执行httpProcessor.process之前我的request.headers是这样子的
这里写图片描述

然后 执行了httpProcessor.process 之后, request. headers变成这样了
这里写图片描述

内容如下


[

    Host: localhost:8088,     Connection: Keep-Alive,     User-Agent: Apache-HttpClient/4.5 (Java/1.7.0_40),     Accept-Encoding: gzip,deflate

]


是不是很眼熟啊, 对了 就是上面服务器第一次获取到的header

然后 下面是第二次请求的httpProcessor.process处理之后的结果


[

    Host: localhost:8088,     Connection: Keep-Alive,     User-Agent: Apache-HttpClient/4.5 (Java/1.7.0_40),     Cookie: JSESSIONID=6F477DD72CD80E3102CA3D13ED03213F; isVisited_16=visited,     Accept-Encoding: gzip,deflate

]


ok, 看到了吧, 结果 已经出现来了, 问题 就在于这个httpProcessor.process

////////////////////////////////////////////////// sepr //////////////////////////////

经过以上的步骤就找到了问题之所在, 下面我们再来详细的瞅瞅到底HttpClient对于cookie的处理吧

我们这里分析一下第一次发送请求, 获取到结果之后, HttpClient对于Cookie的处理, 以及第二次发送请求之前对于”缓存的Cookie”的封装

1. 第一次发送请求得到Response之后对于Cookie的处理
ProtocolExec. execute
这里写图片描述
ImmutableHttpProcessor.process
这里写图片描述
ResponseProcessCookies.process
这里写图片描述
ResponseProcessCookies.processCookies
这里写图片描述

那么照这里看来, 似乎 cookie被保存到了clientContext.cookieStore

那么 他是如何在下一次发送请求的时候注入到cookie到request呢?? 因为”Request.Get.execute“传入的localContext参数可是为null啊,

Request.Get.execute
这里写图片描述

那么 我们接着看一下localContext.cookieStore的来源吧

InternalHttpClient.doExecute
这里写图片描述
InternalHttpClient. setupContext
这里写图片描述

看到了吧, clientContext.cookieStore来自于 InternalHttpClient.cookieStore, 这个InternalHttpClient对象也就是我们前面”Request.Get.execute”中的Executor.CLIENT参数, 因为 发送多次请求 他是”单例”, 因此 多次请求之间的数据 得以传递

2. 那么接下来我们看一下第二次请求的时候, 对于cookie的注入

ProtocolExec. execute
这里写图片描述
ImmutableHttpProcessor.process
这里写图片描述

RequestAddCookies.process
这里写图片描述
这里写图片描述
这里写图片描述

cookieSpec对于给定的cookie进行校验, 判断”缓存的Cookie” 是否属于当前需要请求的域, 以及 相关安全性验证

这里写图片描述

验证完成之后, 放入matchedCookies, 然后 之后 添加到request的header中

好了,, 原因终于找到了, 但是 还有一点, 如果 需要我不想要HttpClient帮我”缓存cookie”呢? 那么 就使用HttpClientBuilder了

HttpClient的子类挺多的, 我们这里 只讨论的是”Request.Get”中使用的”InternalHttpClient”

0 0
原创粉丝点击