当前位置: 首页 > news >正文

4、Httpclient源码解析之HTTP协议

初始化CloseableHttpClient过程中涉及ExecChainHandler & DefaultHttpProcessor,即典型客户端责任链中的请求执行处理器。

责任链中各节点涉及请求处理器【ExecChainHandler】顺序如下:RedirectExec、ContentCompressionExec、HttpRequestRetryExec、ProtocolExec、ConnectExec、MainClientExec。

DefaultHttpProcessor中HttpRequestInterceptor类型的数组【requestInterceptors[]】包含RequestDefaultHeaders、RequestContent、RequestTargetHost、RequestClientConnControl、RequestUserAgent、RequestExpectContinue、RequestAddCookies、RequestAuthCache、ResponseProcessCookies。

1、InternalHttpClient

protected CloseableHttpResponse doExecute(HttpHost target,ClassicHttpRequest request,HttpContext context) {...final HttpClientContext localcontext = HttpClientContext.adapt(context != null ? context : new BasicHttpContext());RequestConfig config = null;if (request instanceof Configurable) {config = ((Configurable) request).getConfig();}if (config != null) {localcontext.setRequestConfig(config);}final HttpRoute route = determineRoute(target, request, localcontext);...final ExecRuntime execRuntime = new InternalExecRuntime(log, connManager, requestExecutor,request instanceof CancellableDependency ? (CancellableDependency) request : null);final ExecChain.Scope scope = new ExecChain.Scope(exchangeId, route, request, execRuntime, localcontext);final ClassicHttpResponse response = this.execChain.execute(ClassicRequestCopier.INSTANCE.copy(request), scope);return CloseableHttpResponse.adapt(response);
}

HttpClientContext:生命周期为单次请求。
execChain:ExecChainElement。按照开头责任链中节点顺序执行。

2、ExecChainElement

class ExecChainElement {
private final ExecChainHandler handler;
private final ExecChainElement next;ExecChainElement(final ExecChainHandler handler, final ExecChainElement next) {this.handler = handler;this.next = next;
}public ClassicHttpResponse execute(final ClassicHttpRequest request,final ExecChain.Scope scope) throws IOException, HttpException {return handler.execute(request, scope, new ExecChain() {//首个节点为RedirectExec@Overridepublic ClassicHttpResponse proceed(final ClassicHttpRequest request,final Scope scope) throws IOException, HttpException {return next.execute(request, scope);}});
}

2.1、RedirectExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {RedirectLocations redirectLocations = context.getRedirectLocations();...RequestConfig config = context.getRequestConfig();for (int redirectCount = 0;;) {ClassicHttpResponse response = chain.proceed(currentRequest, currentScope);...URI redirectUri = this.redirectStrategy.getLocationURI(currentRequest, response, context);...}
}

2.2、ContentCompressionExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {/* Signal support for Accept-Encoding transfer encodings. */if (!request.containsHeader(HttpHeaders.ACCEPT_ENCODING) && requestConfig.isContentCompressionEnabled()) {request.addHeader(acceptEncoding);}ClassicHttpResponse response = chain.proceed(request, scope);...
}

2.3、HttpRequestRetryExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {for (int execCount = 1;; execCount++) {response = chain.proceed(currentRequest, scope);...final HttpEntity entity = request.getEntity();if (entity != null && !entity.isRepeatable()) {return response;}if (retryStrategy.retryRequest(response, execCount, context)) {response.close();final TimeValue nextInterval = retryStrategy.getRetryInterval(response, execCount, context);if (TimeValue.isPositive(nextInterval)) {nextInterval.sleep();}currentRequest = ClassicRequestCopier.INSTANCE.copy(scope.originalRequest);} else {return response;}}
}

如果请求存在重试策略,则通过for循环实现请求多次请求服务端。

2.4、ProtocolExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {for (;;) {//DefaultHttpProcessorhttpProcessor.process(request, request.getEntity(), context);...ClassicHttpResponse response = chain.proceed(request, scope);}
}

2.4.1、DefaultHttpProcessor

for (final HttpRequestInterceptor requestInterceptor : this.requestInterceptors) {requestInterceptor.process(request, entity, context);
}

2.5、ConnectExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {ExecRuntime execRuntime = scope.execRuntime;//InternalExecRuntime...execRuntime.acquireEndpoint(exchangeId, route, userToken, context);//#1do {final HttpRoute fact = tracker.toRoute();step = this.routeDirector.nextStep(route, fact);switch (step) {case HttpRouteDirector.CONNECT_TARGET:execRuntime.connectEndpoint(context);tracker.connectTarget(route.isSecure());break;case HttpRouteDirector.CONNECT_PROXY:execRuntime.connectEndpoint(context);final HttpHost proxy  = route.getProxyHost();tracker.connectProxy(proxy, route.isSecure() && !route.isTunnelled());break;...}} while (step > HttpRouteDirector.COMPLETE);}return chain.proceed(request, scope);
}
  1. 步骤1:涉及获取连接池中的连接。

2.6、MainClientExec

public ClassicHttpResponse execute(ClassicHttpRequest request,ExecChain.Scope scope,ExecChain chain) {ClassicHttpResponse response = execRuntime.execute(exchangeId, request, context);//InternalExecRuntime  #1...if (reuseStrategy.keepAlive(request, response, context)) {// Set the idle duration of this connectionfinal TimeValue duration = keepAliveStrategy.getKeepAliveDuration(response, context);if (this.log.isDebugEnabled()) {final String s;if (duration != null) {s = "for " + duration;} else {s = "indefinitely";}}execRuntime.markConnectionReusable(userToken, duration);} else {execRuntime.markConnectionNonReusable();}return new CloseableHttpResponse(response, execRuntime);
}
  1. 步骤1:参考2.6.1之HttpRequestExecutor。

2.6.1、HttpRequestExecutor

public ClassicHttpResponse execute(ClassicHttpRequest request,HttpClientConnection conn,HttpResponseInformationCallback informationCallback,HttpContext context) {...ClassicHttpResponse response = null;while (response == null) {if (expectContinue) {...} else {response = conn.receiveResponseHeader();//#1 状态行 & 响应头if (streamListener != null) {streamListener.onResponseHead(conn, response);}final int status = response.getCode();...if (status < HttpStatus.SC_SUCCESS) {if (informationCallback != null && status != HttpStatus.SC_CONTINUE) {informationCallback.execute(response, conn, context);}response = null;}}}if (MessageSupport.canResponseHaveBody(request.getMethod(), response)) {//conn:DefaultBHttpClientConnectionconn.receiveResponseEntity(response);//#2 响应体IncomingHttpEntity}return response;
}
  1. 步骤2:解析响应体IncomingHttpEntity,响应体中InputStream类型的属性content其取值为ContentLengthInputStream。
public ClassicHttpResponse receiveResponseHeader() throws HttpException, IOException {final SocketHolder socketHolder = ensureOpen();final ClassicHttpResponse response = this.responseParser.parse(this.inBuffer, socketHolder.getInputStream());// #1final ProtocolVersion transportVersion = response.getVersion();this.version = transportVersion;onResponseReceived(response);final int status = response.getCode();if (response.getCode() >= HttpStatus.SC_SUCCESS) {incrementResponseCount();}return response;
}
  1. 步骤1:首先从连接Socket 获取最原始的输入流,其次将流转化到SessionInputBufferImpl中,最终返回http响应报文中的状态行&响应头。

2、SessionInputBufferImpl & SessionOutputBufferImpl

DefaultBHttpClientConnection实例化过程中触发SessionInputBufferImpl、SessionOutputBufferImpl的实例化。

SessionInputBufferImpl:Abstract base class for session input buffers that stream data from an arbitrary {@link InputStream}. This class buffers input data in an internal byte array for optimal input performance。

3、SocketHolder

Utility class that holds a {@link Socket} along with copies of its {@link InputStream} and {@link OutputStream}。

4、ContentLengthInputStream

Input stream that cuts off after a defined number of bytes【被定义好的字节,其实就是指状态行、响应头】。This class is used to receive content of HTTP messages where the end of the content entity is determined by the value of the {@code Content-Length header}【响应体的字节长度是通过响应头中Content-Length其value决定的】。Entities transferred using this stream can be maximum {@link Long#MAX_VALUE} long【使用此流传输的实体可以是long最大值】。

5、响应体IncomingHttpEntity

6、ResponseEntityProxy

相关文章:

4、Httpclient源码解析之HTTP协议

初始化CloseableHttpClient过程中涉及ExecChainHandler & DefaultHttpProcessor&#xff0c;即典型客户端责任链中的请求执行处理器。 责任链中各节点涉及请求处理器【ExecChainHandler】顺序如下&#xff1a;RedirectExec、ContentCompressionExec、HttpRequestRetryExec…...

浏览器并发行为记录

使用nodejs koa起一个服务&#xff0c;使请求延时返回。 服务端代码 /** 延时 */ exports.timeoutTestData async function (ctx) {console.log(get query:, ctx.request.query);const query ctx.request.query;let timeout query.timeout || 2000;await new Promise(res…...

工厂模式与抽象工厂

原理&#xff1a;逻辑和业务全部封装 不需要细节 只要结果 示例&#xff1a; # 简单工厂 class SimpleFactory:# 产品staticmethoddef product(name):return nameif __name__ "__main__":product SimpleFactory.product("Gitee")print(product) 装饰器…...

什么?你不知道 ConcurrentHashMap 的 kv 不能为 null?

一、背景 最近设计某个类库时使用了 ConcurrentHashMap 最后遇到了 value 为 null 时报了空指针异常的坑。 本文想探讨下以下几个问题&#xff1a; &#xff08;1&#xff09; Map接口的常见子类的 kv 对 null 的支持情况。 &#xff08;2&#xff09;为什么 ConcurrentHashM…...

SQL复习04 | 复杂查询

1. 视图 视图和表的区别&#xff1a; 表保存的是实际的数据视图保存的是SELECT语句 视图的优点&#xff1a; 视图无需保存数据&#xff0c;可节省存储设备的容量可以将频繁使用的SELECT语句保存成视图&#xff0c;可大大提高效率 1.1 创建视图 CREATE VIEW 视图名称&…...

【面试题】Java面试题汇总(无解答)

此内容会持续补充。。。 基础 short s1 1; s1 s1 1;有错吗? short s1 1; s1 1; 有错吗&#xff1f;String str”aaa”,与 String strnew String(“aaa”)一样吗&#xff1f;String 和 StringBuilder、StringBuffer 的区别&#xff1f;Sring最大能存多大内容&#xff1f…...

C++---背包模型---收服精灵(每日一道算法2023.3.11)

注意事项&#xff1a; 本题是"动态规划—01背包"的扩展题&#xff0c;优化的思路不多赘述&#xff0c;dp思路会稍有不同&#xff0c;下面详细讲解。 本题偏向阅读理解&#xff0c;给每种变量归类起名字很有帮助哦。 切记先看思路&#xff0c;再看代码。&#xff08;大…...

day30_JS

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、BOM 三、定时器 四、正则表达式 零、 复习昨日 事件 事件绑定方式鼠标事件 onmouseoveronmouseoutonmousemove 键盘事件 onkeydownonkeyupon…...

【Java学习笔记】19.Java 正则表达式(2)

前言 本章继续介绍Java的正则表达式。 Matcher 类的方法 索引方法 索引方法提供了有用的索引值&#xff0c;精确表明输入字符串中在哪能找到匹配&#xff1a; 序号方法及说明1public int start()返回以前匹配的初始索引。2public int start(int group)返回在以前的匹配操作…...

华为云arm架构轻松安装kubeedge

先安装k8s 华为云arm架构安装k8s(kubernetes) 下载kubeedge需要的软件 官方github下载kubeedge地址 cloudcore.service文件下载地址 注意:下载对应的版本和arm架构 keadm-v1.6.1-linux-arm64.tar.gz 下面的2个文件可以不用下载,安装kubeedge时也会自动去下载到/etc/kubee…...

33--Vue-前端开发-使用Vue脚手架快速搭建项目

一、vue脚手架搭建项目 node的安装: 官方下载,一路下一步 node命令类似于python npm命令类似于pip 使用npm安装第三方模块,速度慢一些,需换成淘宝镜像 以后用cmpm代替npm的使用 npm install -g cnpm --registry=https://registry.npm.taobao.org安装脚手架: cnpm inst…...

TMS WEB Core开发Web应用优势说明

一、Delphi开发Web应用的三大框架如下: IntraWEB适合于WEB前、后端的开发,其自带的网络服务器非常强大、稳定,笔者使用Cesium框架开发的WEB GIS地理信息系统前端不需要Apache Tomcat或Nginx即可稳定运行; uniGUI是对JavaScript库Sencha ExtJS的封装,它带有两套VCL组件包,…...

人工智能简单应用1-OCR分栏识别:两栏识别三栏识别都可以,本地部署完美拼接

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来OCR的分栏识别。 一、文本分栏的问题 在OCR识别过程中&#xff0c;遇到文字是两个分栏的情况确实是一个比较常见的问题。通常情况下&#xff0c;OCR引擎会将文本按照从左到右&#xff0c;从上到下的顺序一行一行地识别…...

Gin框架路由拆分与注册详解析

Gin框架路由拆分与注册详解析1.基本的路由注册2.路由拆分成单独文件或包3.路由拆分成多个文件4.路由拆分到不同的APP1.基本的路由注册 下面最基础的gin路由注册方式&#xff0c;适用于路由条目比较少的简单项目或者项目demo // StatCost 是一个统计耗时请求耗时的中间件 func…...

2020蓝桥杯真题凯撒加密 C语言/C++

题目描述 给定一个单词&#xff0c;请使用凯撒密码将这个单词加密。 凯撒密码是一种替换加密的技术&#xff0c;单词中的所有字母都在字母表上向后偏移 3 位后被替换成密文。即 a 变为 d&#xff0c;b 变为 e&#xff0c;⋯&#xff0c;w 变为z&#xff0c;x 变为 a&#xff0…...

taro+vue3小程序使用v-html渲染的内容为class写了样式无效

taro小程序如果是直接引入的一个less文件是包含scoped&#xff0c;只是当前页面采用。<script setup>import ./index.less</script><view v-html"itehtml" class"article-content"></view>let itehtml"<p class"line…...

MASK-RCNN网络介绍

目录前言一.MASK R-CNN网络1.1.RoIPool和RoIAlign1.2.MASK分支二.损失函数三.Mask分支预测前言 在介绍MASK R-CNN之前&#xff0c;建议先看下FPN网络&#xff0c;Faster-CNN和FCN的介绍&#xff1a;下面附上链接&#xff1a; R-CNN、Fast RCNN和Faster RCNN网络介绍FCN网络介绍…...

导航技术调研(CSDN_0023_20221217)

文章编号&#xff1a;CSDN_0023_20221217 目录 1. 惯性导航 2. 组合导航技术 3. 卡尔曼滤波 1. 惯性导航 惯性导航系统(INS-Inertial Navigation System)是上个世纪初发展起来的。惯性导航是一种先进的导航方法&#xff0c;但实现导航定位的原理却非常简单&#xff0c;它是…...

买卖股票的最佳时机 I II III IV

121. 买卖股票的最佳时机 自己的思路&#xff1a;采用求最长连续子串和题目的思路 class Solution {public int maxProfit(int[] prices) {if(prices.length 1) return 0;int[] nums new int[prices.length - 1];for(int i 0;i < prices.length - 1;i){nums[i] prices[…...

STM32—LCD1602

LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 第 1 脚: VSS 为电源地 第 2 脚: VDD 接 5V 正电源 第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱&#xff0c;接地时对比度最…...

英雄算法学习路线

文章目录零、自我介绍一、关于拜师二、关于编程语言三、算法学习路线1、算法集训1&#xff09;九日集训2&#xff09;每月算法集训2、算法专栏3、算法总包四、英雄算法联盟1、英雄算法联盟是什么&#xff1f;2、如何加入英雄算法联盟&#xff1f;3、为何会有英雄算法联盟&#…...

【设计模式】备忘录模式和迭代器模式

备忘录模式和迭代器模式备忘录模式代码示例迭代器模式代码示例使用迭代器遍历集合的同时不能删除/增加元素总结备忘录模式 备忘录模式&#xff0c;也叫快照&#xff08;Snapshot&#xff09;模式。 在 GoF的《设计模式》⼀书中&#xff0c;备忘录模式是这么定义的&#xff1a;…...

rapidcsv 写csv文件实例

csv实质是一个文本文件&#xff0c;可以使用rapidcsv写文件操作&#xff0c;如下实例&#xff1a; 第一行实质是从-1行开始&#xff0c;列是从0开始 #include "rapidcsv.h" #include <string> using namespace std; void CMFCApplication1Dlg::OnBnClickedBu…...

数据库--进阶篇--9--存储引擎

MySQL体系结构 索引是在引擎层&#xff0c;所以不同的存储引擎&#xff0c;它的索引结构不同。 存储引擎简介 存储引擎就是存储数据、建立所以、更新/查询数据等技术的实现方式。存储引擎是基于表的&#xff0c;而不是基于库的&#xff0c;所以存储引擎也可以被称为表类型。 …...

物品的管理的隐私政策

本应用尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务&#xff0c;本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外&#xff0c;在未征得您事先许可的情况下…...

深度解析首个Layer3 链 Nautilus Chain,有何优势?

以流支付为主要概念的Zebec生态&#xff0c;正在推动流支付这种新兴的支付方式向更远的方向发展&#xff0c;该生态最初以Zebec Protocol的形态发展&#xff0c;并从初期的Solana进一步拓展至BNB Chian以及Near上。与此同时&#xff0c;Zebec生态也在积极的寻求从协议形态向公链…...

配对变量t检验

区别双变量t检验&#xff0c;见&#xff1a;https://mp.csdn.net/postedit/100640098 配对变量为两两相关的变量&#xff1a;如敷药前后体重变化。 要求&#xff1a;两变量服从正态分布。 SPSS演练 打开数据文件&#xff1a;ptest.sav 载地址&#xff1a;https://download.c…...

蓝桥杯三月刷题 第八天

文章目录&#x1f4a5;前言&#x1f609;解题报告&#x1f4a5;分数&#x1f914;一、思路:&#x1f60e;二、代码&#xff1a;&#x1f4a5;回文日期&#x1f914;一、思路:&#x1f60e;二、代码&#xff1a;&#x1f4a5;迷宫&#x1f914;一、思路:&#x1f60e;二、代码&a…...

EXCEL技能点3-常用技能1

1 引用格式 公式中引用单元格或者区域时,引用的类型可分为以下三种: 绝对引用 相对引用 混合引用 在Excel里&#xff0c;每个单元格都有一个编码&#xff0c;就像人的身份证一样&#xff0c;在Excel里是按照行列进行编码&#xff0c;例如A1就是第一列的第一行。 那么我们想要引…...

经典分类模型回顾16-AlexNet实现垃圾分类(Tensorflow2.0版)

AlexNet是2012年由亚历克斯克里斯托夫&#xff08;Alex Krizhevsky&#xff09;等人提出的一种卷积神经网络结构&#xff0c;它在ImageNet图像识别比赛中获得了第一名&#xff0c;标志着卷积神经网络的崛起。 AlexNet的结构包括8层网络&#xff0c;其中前5层为卷积层&#xff…...