13 关于HttpClient自动保存Cookie

前言

下面是我以前想做的一个专门为了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//          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
13 关于HttpClient自动保存Cookie_第1张图片

然后 问题出来了, 在执行httpProcessor.process之前我的request.headers是这样子的
13 关于HttpClient自动保存Cookie_第2张图片

然后 执行了httpProcessor.process 之后, request. headers变成这样了
13 关于HttpClient自动保存Cookie_第3张图片

内容如下


[

    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
13 关于HttpClient自动保存Cookie_第4张图片
ImmutableHttpProcessor.process
这里写图片描述
ResponseProcessCookies.process
13 关于HttpClient自动保存Cookie_第5张图片
ResponseProcessCookies.processCookies
13 关于HttpClient自动保存Cookie_第6张图片

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

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

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

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

InternalHttpClient.doExecute
13 关于HttpClient自动保存Cookie_第7张图片
InternalHttpClient. setupContext
这里写图片描述

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

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

ProtocolExec. execute
13 关于HttpClient自动保存Cookie_第8张图片
ImmutableHttpProcessor.process
这里写图片描述

RequestAddCookies.process
13 关于HttpClient自动保存Cookie_第9张图片
13 关于HttpClient自动保存Cookie_第10张图片
13 关于HttpClient自动保存Cookie_第11张图片

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

13 关于HttpClient自动保存Cookie_第12张图片

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

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

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

你可能感兴趣的:(05,问题)