欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深度剖析 Spring Web 框架中的 HTTP 源代码

最编程 2024-02-23 18:55:14
...

Spring框架之spring-web http源码完全解析

        Spring-web是Spring webMVC的基础,由http、remoting、web三部分组成。

        http:封装了http协议中的client/server端的request请求/response响应,编解码,一些格式的转换(如cbor、Rss、json、xml)。

        remoting:远程调用,包括caucho、httpinvoker、jaxws。caucho公司提出的基于HTTP实现的两种远程服务Burlap和hessian。HttpInvoker是spring 框架中基于 HTTP的一个远程调用模型,只能用于Spring框架。jaxws是Sun推出的web services协议栈。

        web:包含了和web相关的accept、bind、client、context、cors、filter、jsf、method、multipart、server、util。

        Spring-web是Spring webMVC的基础,HTTP用于Web浏览器和Web服务器之间的双工通信,所以Spring-web http模块又是Spring-web的基础,它包含五个模块:

        1、 http 封装的基础,如httpHeader、HttpEntity 、HttpMessage 、MediaType 、HttpMethod 、httpStatus、HttpCookie等;

        2、client端的request请求(发送出去的)及response响应(接收到的);

        3、 server端的request请求(接收到的)及response响应(发送出去的);

        4、格式的转换,如json,rss,xml等。

        5、 编/解码器。

        本文基于version为5.2.4.BUILD-SNAPSHOT的Spring源码版本进行分析,主要从HTTP基础及Spring-web http五个子模块共六部分进行分析。

一、HTTP基础

(1)HTTP协议:HTTP(Hypertext Transfer Protocol,超文本传输协议)是在万维网上进行通信时所使用的协议方案,基于TCP/IP的应用层协议。HTTP有很多应用,最著名的就是用于Web浏览器和Web服务器之间的双工通信。客户端向服务器发送HTTP请求,服务器在HTTP响应中回送所请求的数据。

(2)MIME类型:因特网上有数千中不同的数据类型,HTTP给每种要通过Web传输的对象都打上MIME类型的数据格式标签。MIME类型是一种文本标记,表示一种主要的对象类型和一个特定的子类型,中间由一条斜杠分隔。如text/html标记HTML 格式的文本文档;由text/plain标记普通的ASCII 文本文档;image/jpeg标记JPEG 格式的图片。

(3)URL:统一资源定位符。每个服务器资源都有一个名字,在世界范围内唯一的标识并定位信息资源。

(4)HTTP方法:每条HTTP请求报文都包含一个方法,这个方法告诉服务器要执行什么动作,比如获取一个页面、运行一个网关程序或者删除一个文件。五种常见的HTTP方法:

        1、GET 从服务器向客户端发送命名资源;

        2、PUT 将来自客户端的数据存储到一个命名的服务器资源中去;

        3、DELETE 从服务器中删除命名资源;

        4、POST 将客户端数据发送到一个服务器网关应用程序;

        5、HEAD 仅发送命名资源响应中的HTTP 首部。

(5)状态码(HTTP Status Code):每条HTTP响应报文返回时都会携带一个状态码,是一个三位数字的代码,告知客户端请求是否成功,或者是否需要采取其他动作。

        1xx消息:这一类型的状态码,代表请求已被接受,需要继续处理。

        2xx成功:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

        3xx重定向:这类状态码代表需要客户端采取进一步的操作才能完成请求。

        4xx客户端错误:这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。

        5xx服务器错误:表示服务器无法完成明显有效的请求。

(6)HTTP报文: HTTP报文是由一行行的简单字符串组成,都是纯文本,不是二进制代码,可以方便进行读写。分为HTTP请求和响应报文,无其他类型的HTTP报文,请求和响应报文格式很相似,包括起始行、首部字段、主体3个部分。

        1、起始行:报文的第一行就是起始行,在请求报文中用来说明要做些什么,在响应报文中说明出现了什么情况。

        2、首部字段:起始行后面有零个或多个首部字段。每个首部字段都包含一个名字和一个值,为了便于解析,两者之间用冒号来分隔。首部以一个空行结束。添加一个首部字段和添加新行一样简单。

        3、主体:空行之后就是可选的报文主体了,其中包含了所有类型的数据。请求主体中包括了要发送给Web 服务器的数据;响应主体中装载了要返回给客户端的数据。起始行和首部都是文本形式且都是结构化的,而主体则不同,主体中可以包含任意的二进制数据,比如图片、视频、音轨、软件程序,文本等。

(7)请求报文(request message):从客户端发往服务器的HTTP报文。

请求报文示例:

        GET/sample.Jsp HTTP/1.1

        Accept:image/gif.image/jpeg,*/*

        Accept-Language:zh-cn

        Connection:Keep-Alive

        Host:localhost

        User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)

        Accept-Encoding:gzip,deflate

         

        username=jinqiao&password=1234

        1、起始行:请求报文的起始行又叫请求行,请求服务器对资源做一些操作,包含了一个方法和一个请求的URL。这个方法描述了服务器应该执行的操作,请求URL描述了要对哪个资源执行这个方法。请求行中还包含HTTP 的版本,用来告知服务器,客户端使用的是哪种HTTP。上例中“GET”代表请求方法,“/sample.jsp”表示URI,“HTTP/1.1代表协议和协议的版本。

        2、请求头:跟在起始行后面的就是零个、一个或多个HTTP 首部字段。包含客户端的环境及请求正文相关信息。

        3、请求体:首部字段和主体之间有一个空行,表示首部字段结束,接下来是主体。上例请求正文中包含客户提交的查询字符串信息.

(8)响应报文(response message):从服务器发往客户端的报文。

响应报文示例:

        HTTP/1.0 200 OK

        Date: Sun, o1 Oct 2000 23:25:17 GMT

        Server: Apache/1.3.11 BSafe-SSL/1.38 (Unix)

        Last-modified: Tue, 04 Jul 2000 09:46:21 GMT

        Content-length: 403

        Content-type: text/html

           

        Hi! I’m a message!

        1、起始行:响应报文的起始行又称响应行,包含了响应报文使用的HTTP 版本、数字状态码,以及描述操作状态的文本形式的原因短语。上例中:HTTP 版本为HTTP/1.0,状态码为200(表示成功),原因短语为OK,表示文档已经被成功返回了。

        2、响应头:跟在起始行后面的就是零个、一个或多个HTTP 首部字段。

        3、响应体:第三部分是可选的实体主体部分。实体的主体是HTTP 报文的负荷,就是HTTP 要传输的内容。可以承载多种类型的数字数据,如图片、视频、HTML 文档、软件应用程序、信用卡事务、电子邮件等。

(9)浏览器通过HTTP请求服务器HTML 资源步骤:

        1、 浏览器从URL 中解析出服务器的主机名;

        2、浏览器将服务器的主机名转换成服务器的IP 地址;

        3、浏览器将端口号(如果有的话)从URL 中解析出来;

        4、浏览器建立一条与Web 服务器的TCP 连接;

        5、 浏览器向服务器发送一条HTTP 请求报文;

        6、 服务器向浏览器回送一条HTTP 响应报文;

        7、关闭连接,浏览器显示文档。

 

二、http封装的基础

(1)HttpHeaders:表示HTTP报文首部,首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。HTTP首部字段是由首部字段名和字段值构成的,中间用冒号分隔(首部字段名: 字段值)。该类同时也为首部字段提供了get/set方法。HTTP 首部字段根据实际用途被分为以下 4 种类型:

        1、通用首部字段(General Header Fields):请求报文和响应报文两方都会使用的首部。

        2、请求首部字段(Request Header Fields):从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。

        3、响应首部字段(Response Header Fields):从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。

        4、实体首部字段(Entity Header Fields):针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。

(2)ReadOnlyHttpHeaders:只读类型的HTTP报文首部。继承自HttpHeaders,只能读取,不能写入。

 

(3)HttpEntity:表示HTTP request或者response实体,由header首部和body主体两部分组成。

(4)RequestEntity:继承自HttpEntity,Request请求实体,在HttpEntity基础上增加了两个属性:HttpMethod类和URI类。HttpMethod枚举了HTTP请求报文的几种方法:GET/HEAD/POST/PUT/PATCH/DELETE/OPTIONS/TRACE。URI(java.net.URI)表示统一资源标识符(URI)引用。HttpEntity主要被RestTemplate使用(package org.springframework.web.client,RestTemplate 对 http 的封装类似 JdbcTemplate 对 jdbc 的封装,能够以 rest 风格的方式,以 GET/POST/PUT/DELETE/HEAD/ OPTIONS 等不同的方式向服务器发起HTTP 请求)。

(5)ResponseEntity:继承自HttpEntity,Response响应实体,在HttpEntity基础上增加了一个属性HttpStatus。HttpStatus枚举了HTTP的状态码。1xx消息、2xx成功、3xx重定向、4xx客户端错误、5xx服务器错误,每条HTTP响应报文返回时都会携带一个状态码,告知客户端请求是否成功,或者是否需要采取其他动作。同样,该类主要被RestTemplate使用。

 

(6)HttpMessage:HTTP request请求报文和response响应报文的父接口。提供了一个方法getHeaders(),获得该报文的首部HttpHeaders。

(7)HttpRequest(extends HttpMessage):表示一个HTTP request请求报文。在父类基础上新增了两个函数:getMethod()获取报文的HttpMethod,描述了服务器应该执行的操作方法;getURI()获取该报文的URL,描述了要对哪个资源执行上述方法。

(8)HttpInputMessage(extends HttpMessage):表示一条接收到的HTTP报文,从服务器端来看就是接收到request报文,从客户端来看就是接收到response报文。在父接口HttpMessage定义的函数getHeaders()基础上新增了一个函数getBody(),获得报文的主体,返回类型是可读的字节输入流InputStream(java.io.InputStream)。

(9)HttpOutputMessage(extends HttpMessage):表示一条发送出去的HTTP报文,从服务器端来看就是发送出去的response报文,从客户端来看就是发送出去的request报文。在父接口HttpMessage定义的函数getHeaders()基础上新增了一个函数getBody(),获得报文的主体,返回类型是可写的字节输入流OutputStream(java.io.OutputStream)。

(10)StreamingHttpOutputMessage(extends HttpOutputMessage):继承自HttpOutputMessage,该报文允许设置一个streaming流类型的报文主体。相应的,这种报文类型也就不支持getBody()函数读取报文主体了。

(11)ReactiveHttpInputMessage(extends HttpMessage):一个响应式的HTTP input报文,会将这个input报文当做Publisher发布者暴露。这个接口主要会被服务器端接收到的request请求报文类或者客户端接收到的response响应报文类实现。reactive programming(响应式编程)是相对于imperative programming(命令式编程)而言的,一种异步编程风格,它关注数据流和变化的传播。

(12)ReactiveHttpOutputMessage(extends HttpMessage):一个响应式的HTTP output报文,会将这个output报文当做Publisher发送出去。这个接口主要会被服务器端发送的response响应报文类或者客户端发送的request请求报文类实现。

(13)ZeroCopyHttpOutputMessage(extends ReactiveHttpOutputMessage):在类ReactiveHttpOutputMessage继承上增加了对零拷贝的文件传输的支持。零拷贝技术(Zero-Copy)是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手 。零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换 。

 

(14)MediaType:继承自MimeType(org.springframework.util.MimeType),在父类MimeType基础上增加了对在HTTP规范中定义的一些高质量的参数提供的方法支持。媒体类型决定浏览器将以何种形式对资源进行解析。常见的媒体格式类型(<type>/<subtype>)如下:

        text/html: HTML格式

        text/plain:纯文本格式

        image/gif:gif图片格式

        application/pdf:pdf格式

        application/octet-stream:二进制流数据

        ...

 Content-Type实体头部用于指示资源的MIME类型media type。如:

        Content-Type: text/html; charset=utf-8

        Content-Type: multipart/form-data; boundary=something

(15)MediaTypeEditor:继承自PropertyEditorSupport(java.beans.PropertyEditorSupport),自动的把字符串类型的说明(如"text/html")转换成MediaType对象。

(16)MediaTypeFactory:该工厂类用来从资源句柄或者文件名中解析出MediaType对象。

(17)InvalidMediaTypeException:执行解析函数parseMediaType(String)时遇到一个非法的media type抛出的异常。

 

(18)HttpMethod:枚举了HTTP request 几种方法:GET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS、TRACE。该枚举类型主要被ClientHttpRequest(package  org.springframework.http)和RestTemplate(package org.springframework.web.client)使用。

        枚举是Java1.5引入的新特性,通过关键字enum来定义枚举类。枚举类是一种特殊类,它和普通类一样可以使用构造器、定义成员变量和方法,也能实现一个或多个接口,但枚举类不能继承其他类。

(19)HttpStatus:枚举了HTTP的状态码。通过提供的series()函数可以得到该状态码属于哪一大类:INFORMATIONAL(1xx消息)、SUCCESSFUL(2xx成功)、REDIRECTION(3xx重定向)、CLIENT_ERROR(4xx客户端错误)、SERVER_ERROR(5xx服务器错误)。

(20)HttpRange:使用Range首部来表示一个HTTP(byte) range。HTTP通过首部Range属性允许客户端只请求文档的一部分,或者说某个范围。

        GET /bigfile.html HTTP/1.1

        Host: www.joes-hardware.com

        Range: bytes=4000-

        User-Agent: Mozilla/4.61 [en] (WinNT; I)

        ...

        在上例中,客户端请求的是文档开头4000 字节之后的部分(不必给出结尾字节数,因为请求方可能不知道文档的大小)。在客户端收到了开头的4000 字节之后就失败的情况下,可以使用这种形式的范围请求。

        还可以用Range 首部来请求多个范围(这些范围可以按任意顺序给出,也可以相互重叠)。例如,假设客户端同时连接到多个服务器,为了加速下载文档而从不同的服务器下载同一个文档的不同部分。对于客户端在一个请求内请求多个不同范围的情况,返回的响应也是单个实体,它有一个多部分主体及Content-Type: multipart/byteranges 首部。Range 首部在流行的点对点(Peer-to-Peer,P2P)文件共享客户端软件中得到广泛应用,它们从不同的对等实体同时下载多媒体文件的不同部分。

(21)CacheControl:控制缓存的开关,用于标识请求或响应中是否开启了缓存,使用了哪种缓存方式。

1、在请求中使用Cache-Control时,可选的值有:

        no-cache:告知(代理)服务器不直接使用缓存,要求向原服务器发起请求。

        no-store:所有内容都不会被保存到缓存或Internet临时文件中。

        max-age=delta-seconds:告知服务器客户端希望接收一个存在时间不大于delta-seconds秒的资源。

        max-stale[=delat-seconds] :告知(代理)服务器客户端愿意接收一个超过缓存时间的资源,若有定义delta-seconds则为delta-seconds秒,若没有则为任意超出时间。

        min-fresh=delta-seconds:告知(代理)服务器客户端希望接收一个在小于delta-seconds秒内被更新过的资源。

        no-transform:告知(代理)服务器客户端希望获取试题数据没有被转换(比如压缩)过的资源。

        only-if-cached:告知(代理)服务器客户端希望获取缓存的内容(若有),而不用向服务器发去请求。

        cache-extension:自定义拓展值,若服务器不识别该值将被忽略掉。

2、在响应中使用Cache-Control时,可选的值有:

        public:表明任何情况下都得缓存该资源(即使是需要HTTP认证的资源)。

        Private[=”field-name”] :表明返回报文中全部或部分(若指定了field-name则为field-name的字段数据)仅开放给某些用户(服务器指定的share-user,如代理服务器)做缓存使用,其他用户则不能缓存这些数据。

        no-cache:不直接使用缓存,要求向服务器发起请求。

        no-store:所有内容都不会被保存到缓存或Internet临时文件中。

        no-transform:告知客户端缓存文件时不得对实体数据做任何改变。

        only-if-cached:告知(代理)服务器客户端希望获取缓存的内容(若有),而不用向原服务器发去请求。

        must-revalidate:当前资源一定是向原服务器发去验证请求的,若请求失败会返回504(而非代理服务器上的缓存)

        proxy-revalidate:与must-revalidate类似,但仅能应用于共享缓存(如代理)。

        max-age=delta-seconds:告知客户端该资源在delta-seconds秒内是新鲜的,无需向服务器发请求。

        s-maxage=delta-seconds:同max-age,但仅应用于共享缓存(如代理)

        cache-extension:自定义拓展值,若服务器不识别该值将被忽略掉。

(22)ContentDisposition:该类表示在RFC 6266中定义的属性Content-Disposition。Content-Disposition 属性是作为对下载文件的一个标识字段,有两种类型:inline 和 attachment。inline :将文件内容直接显示在页面;attachment:弹出对话框让用户下载。RFC 6266正式将Content-Disposition纳入 HTTP 标准。

(23)HttpLogging:如果"org.springframework.web"日志功能开启,但是"org.springframework.http"日志功能没有开始,那么此时创建一个共享的日志记录器(命名为org.springframework.web.HttpLogging),用来记录和HTTP相关的日志。这也就是说"org.springframework.web"会开启所有web日志记录器,包括一些低层级的包(如"org.springframework.http")和模块(比如来自于spring-core被包装进EncoderHttpMessageWriter或DecoderHttpMessageReader的编解码器)。

(24)HttpCookie:用来表示一条HTTP cookie,以name-value(名称-键值对)形式表示。

        HTTP协议是无状态的协议,一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足,是http协议的一个扩展。

        有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie(响应报文首部)以及Cookie(请求报文首部)。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。

(25)ResponseCookie:继承自HttpCookie,增加了Set-Cookie 响应首部的一些属性。下面是Set-cookie一个简单的例子:

        HTTP/1.0 200 OK

        Set-cookie: id="34294"; domain="joes-hardware.com"

        Content-type: text/html

        Content-length: 1903

        最初的cookie 规范是由网景公司定义的。这些“ 版本0” 的cookie 定义了Set-Cookie 响应首部、cookie 请求首部以及用于控制cookie 的字段。版本0(网景)的Set-Cookie属性:

        1、NAME=VALUE:强制的,服务器可以创建任意的NAME=VALUE关联,在后续对站点的访问中会将其送回给服务器。

        2、Expires:可选的,该属性用来指定一个日期字符串,用来定义cookie的实际生存期。一旦到了过了生存日期,就不再存储或者发布这个cookie了。

        3、Domain:可选的。浏览器只向指定域中的服务器发送cookie。

        4、Path:可选的。这个属性可以为服务器上特定的文档分配cookie。

        5、Secure:可选的。如果包含了这一属性,就只有在HTTP使用SSL安全连接时才会发送cookie。

 

三、client端的request请求(发送出去的)/response响应(接收到的)

        client端的类主要有三种:

        ClientHttpRequest表示一个客户端发送的HTTP request请求报文(包括基本实现类及支持Buffering、Streaming、Async、StreamingAsync、BufferingAsync拓展类)。

        ClientHttpResponse表示一个客户端接收到的HTTP response响应报文。(包括基本实现类和支持Async拓展类)。

        ClientHttpRequestFactory用来创建ClientHttpRequest的工厂(包括基本实现类和支持Async拓展类)。

        上述又分为基于jkd自带功能、Apache的HttpClient、OkHttp3、Netty4的实现。使用Apache的HttpClient、OkHttp3、Netty4都可,但这些都需要额外导包,默认情况下Spring使用的是java.net.HttpURLConnection。

(一)http/client/

接口

(1)ClientHttpRequest:表示一个客户端的request请求报文。继承自HttpRequest、 HttpOutputMessage(因为从客户端看request是发送出去的,所以继承自HttpOutputMessage。同理,客户端的ClientHttpResponse是接收到的报文,继承自HttpInputMessage)。通过ClientHttpRequestFactory工厂的实现类创建。该接口定义了一个函数execute(),函数的返回类型就是ClientHttpResponse。

(2)ClientHttpResponse:表示客户端接收到的HTTP response响应报文。继承自HttpInputMessage、Closeable。通过执行ClientHttpRequest的execute()函数获得。

(3)ClientHttpRequestFactory:创建ClientHttpRequest对象的工厂。定义了一个函数createRequest(URI, HttpMethod),根据URI和HttpMethod创建出一个ClientHttpRequest来发送请求。

(4)ClientHttpRequestInitializer:回调接口,在ClientHttpRequest使用之前先对其初始化。

(5)ClientHttpRequestExecution:表示客户端HTTP request报文执行(execute)的上下文。主要在ClientHttpRequestInterceptor使用,用来在一个拦截器链上调用下一个拦截器,如果到了拦截器末尾,执行request本身。

(6)ClientHttpRequestInterceptor:客户端的Http request请求拦截器,在Http消息发送到服务器前,该方法被调用,对Http Request报文做些处理,比如加头,更改请求的URL,授权等等。对于客户端接收到的ClientHttpResponse也能处理。

 

(7)AsyncClientHttpRequest:继承自HttpRequest、HttpOutputMessage,表示客户端一个异步的HTTP request请求,通过工厂类创建。(Spring4.0新增,Spring 5.0中废弃,使用org.springframework.web.reactive.function.client.ClientRequest替代)

应用层的网络模型有同步与异步。同步意味当前线程是阻塞的,只有本次请求完成后才能进行下一次请求;异步意味着所有的请求可以同时塞入缓冲区,不阻塞当前的线程。

(8)AsyncClientHttpRequestFactory:创建AsyncClientHttpRequest的工厂,。通过函数createAsyncRequest(URI, HttpMethod)创建。(Spring4.0新增,Spring 5.0中废弃,使用org.springframework.http.client.reactive.ClientHttpConnector替代)

(9)AsyncClientHttpRequestExecution:ClientHttpRequestExecution异步拓展。(Spring4.3新增,Spring 5.0中废弃,使用org.springframework.web.reactive.function.client.ExchangeFilterFunction替代)

(10)AsyncClientHttpRequestInterceptor:ClientHttpRequestInterceptor异步拓展。(Spring4.3新增,Spring 5.0中废弃,使用org.springframework.web.reactive.function.client.ExchangeFilterFunction替代)

 

抽象类

(11)AbstractClientHttpRequest:实现接口ClientHttpRequest,确保首部和报文体不会多次写入。

(12)AbstractBufferingClientHttpRequest:继承自AbstractClientHttpRequest。在request请求报文发送出去之前,缓存request body,内部private ByteArrayOutputStream bufferedOutput变量保存了request body的内容,避免流的二次读取会导致读取不到数据。

(13)AbstractAsyncClientHttpRequest:实现 AsyncClientHttpRequest接口的抽象类。( Spring 5.0中废弃,使用org.springframework.http.client.reactive. AbstractClientHttpRequest替代。)

(14)AbstractBufferingAsyncClientHttpRequest:同时拓展了异步和缓存功能的request报文,继承自AbstractAsyncClientHttpRequest。(Spring 5.0中废弃,无直接替代者)。

 

(15)AbstractClientHttpResponse:实现接口ClientHttpResponse。

(16)AbstractClientHttpRequestFactoryWrapper:装饰抽象类,实现接口ClientHttpRequestFactory,装饰另一个request factory。装饰模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。装饰类一般是一个抽象类,属性里有一个private变量指向ClientHttpRequestFactory,通过构造函数传递给被该修饰者,createRequest方法委托给被修饰者执行。

 

装饰器类

(17)BufferingClientHttpRequestWrapper:包装另外一个request。

(28)BufferingClientHttpResponseWrapper:实现ClientHttpResponse接口。考虑到多次调用getBody(),将接收到的response报文的body部分读入到内存中。

(19)BufferingClientHttpRequestFactory:ClientHttpRequestFactory的装饰器,使得具有缓存的能力。若开启缓存功能(有开关可控),会使用BufferingClientHttpRequestWrapper包装原来的ClientHttpRequest。这样发送请求后得到的是BufferingClientHttpResponseWrapper响应。

 

(20)InterceptingClientHttpRequest:包装了ClientHttpRequest,支持HTTP 请求拦截器 ClientHttpRequestInterceptor。该类重写了executeInternal方法,通过内部类InterceptingRequestExecution实现interceptors顺序执行。该内部类中的的execute()方法的特点是:若存在拦截器,交给给拦截器去执行发送请求return nextInterceptor.intercept(request, body, this),否则就自己上。

(21)InterceptingAsyncClientHttpRequest:包装了AsyncClientHttpRequest,该类重写了executeInternal方法,通过内部类AsyncRequestExecution实现AsyncClientHttpRequestInterceptor顺序执行。该内部类中的的executeAsync()方法的特点是:若存在拦截器,交给给拦截器去执行发送请求:

        return interceptor.intercept(request, body, this);

否则就自己上:

        delegate = requestFactory.createAsyncRequest(uri, method);

        return delegate.executeAsync();

(22)InterceptingClientHttpRequestFactory:继承自AbstractClientHttpRequestFactoryWrapper。包装ClientHttpRequestFactory,以支持ClientHttpRequestInterceptor(客户端的Http request请求拦截器,在Http消息发送到服务器前,该方法被调用,对Http Request报文做些处理)。

(23)InterceptingAsyncClientHttpRequestFactory:实现接口AsyncClientHttpRequestFactory。包装AsyncClientHttpRequestFactory,以支持AsyncClientHttpRequestInterceptor。(Spring 5.0,废弃,无代替者)

 

        在介绍下面类之前,先总体介绍下ClientHttpRequest和ClientHttpRequestFactory在不同库下的实现:

        ClientHttpRequest它代表请求的客户端,该接口继承自HttpRequest、HttpOutputMessage,只有一个ClientHttpResponse execute() throws IOException方法。其中HttpUrlConnection 、OkHttp3、Netty、HttpComponents对它都有实现。默认情况下Spring使用的是java.net.HttpURLConnection,也可以使用OkHttp3、Netty4、Apache的HttpClient,但这些都需要额外导包。

        ClientHttpRequestFactory是一个函数式接口,用于根据URI和HttpMethod创建出一个ClientHttpRequest来发送请求。根据使用底层http库的不同可以分为:

        1、SimpleClientHttpRequestFactory:Spring内置ClientHttpRequestFactory默认的实现,它使用JDK工具(来自java.net包的类),因此不依赖于第三方库。

        2、OkHttp3ClientHttpRequestFactory:封装OkHttp 3.x

        3、Netty4ClientHttpRequestFactory:封装Netty 4。(Spring 5.0中废弃,使用org.springframework.http.client.reactive.ReactorClientHttpConnector替代)。

        4、HttpComponentsClientHttpRequestFactory:封装Apache的HttpClient。

 

使用JDK内置库

(24)SimpleBufferingClientHttpRequest:ClientHttpRequest接口的实现类,带缓冲功能。通过SimpleClientHttpRequestFactory创建。

(25)SimpleStreamingClientHttpRequest:ClientHttpRequest接口的实现类,能执行流处理请求,通过SimpleClientHttpRequestFactory创建。

(26)SimpleBufferingAsyncClientHttpRequest:继承自AbstractBufferingAsyncClientHttpRequest,通过SimpleClientHttpRequestFactory创建。

(27)SimpleStreamingAsyncClientHttpRequest:继承自AbstractAsyncClientHttpRequest,能执行流处理请求,通过SimpleClientHttpRequestFactory创建。

(28)SimpleClientHttpResponse:ClientHttpResponse接口实现类,通过执行SimpleBufferingClientHttpRequest的函数execute()或者SimpleStreamingClientHttpRequest的函数execute()获得。

(29)SimpleClientHttpRequestFactory:ClientHttpRequestFactory接口的实现类,继承自ClientHttpRequestFactory和AsyncClientHttpRequestFactory。重写了ClientHttpRequestFactory的createRequest()函数(用来生成上面24、25两种类型的request)和AsyncClientHttpRequestFactory的createAsyncRequest()函数(用来生成上面26、27两种类型的request)。

 

使用OkHttp 3.x框架

        OkHttp是一款优秀的HTTP框架,一个处理网络请求的开源项目,是安卓端的轻量级框架,由移动支付Square公司贡献。支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题。导包示例:

        <dependency>

            <groupId>com.squareup.okhttp3</groupId>

            <artifactId>okhttp</artifactId>

            <version>3.14.0</version>

        </dependency>

(30)OkHttp3ClientHttpRequest:基于OkHttp 3.x的ClientHttpRequest接口的实现类。通过OkHttp3ClientHttpRequestFactory创建。

(31)OkHttp3AsyncClientHttpRequest:基于OkHttp 3.x的AsyncClientHttpRequest接口的实现类。通过OkHttp3ClientHttpRequestFactory创建。(Spring 5.0中废弃,无替代者)。

(32)OkHttp3ClientHttpResponse:基于OkHttp 3.x的ClientHttpResponse接口实现类。通过执行OkHttp3ClientHttpRequest的executeInternal()函数获得。

(33)OkHttp3ClientHttpRequestFactory:ClientHttpRequestFactory接口的实现类,基于OkHttp 3.x创建request,createRequest()函数创建OkHttp3ClientHttpRequest;createAsyncRequest()函数创建OkHttp3AsyncClientHttpRequest。

 

使用Netty 4框架

        Netty是由JBOSS提供给的一个java开源框架。Netty提供异步的、事件驱动的网络应用框架和工具,用以快速开发高性能、高可靠的网络服务器和客户端程序。导包示例:

        <dependency>

            <groupId>io.netty</groupId>

            <artifactId>netty-all</artifactId>

            <version>5.0.0.Alpha2</version>

        </dependency>

(34)Netty4ClientHttpRequest:基于Netty 4的ClientHttpRequest接口的实现类,通过Netty4ClientHttpRequestFactory创建。

(35)Netty4ClientHttpResponse:基于Netty 4的ClientHttpResponse接口的实现类。

(36)Netty4ClientHttpRequestFactory :ClientHttpRequestFactory接口的实现类,基于Netty 4创建Netty4ClientHttpRequest。

 

使用Apache的HttpClient框架

        Apache开源组织的HttpComponents 也就是以前的httpclient项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端/服务器编程工具包,支持 HTTP 协议最新的版本和建议。现在的 HttpComponents 包含多个子项目:HttpComponents Core、HttpComponents Client、HttpComponents AsyncClient、Commons HttpClient。导包示例:

        <dependency>

            <groupId>org.apache.httpcomponents</groupId>

            <artifactId>httpclient</artifactId>

            <version>4.5.10</version>

        </dependency>

(37)HttpComponentsClientHttpRequest:基于Apache HttpComponents HttpClient的ClientHttpRequest接口的实现类。通过(42)HttpComponentsClientHttpRequestFactory创建。

(38)HttpComponentsStreamingClientHttpRequest:基于Apache HttpComponents HttpClient的执行流处理请求的ClientHttpRequest接口的实现类。通过(42)HttpComponentsClientHttpRequestFactory创建。

(39)HttpComponentsAsyncClientHttpRequest:基于Apache HttpComponents HttpAsyncClient的ClientHttpRequest接口的实现类,通过(43)HttpComponentsAsyncClientHttpRequestFactory创建。(Spring 5.0中废弃,无替代者)

(40)HttpComponentsClientHttpResponse:基于Apache HttpComponents HttpClient的ClientHttpResponse接口的实现类。通过(37)HttpComponentsClientHttpRequest的executeInternal()函数创建。

(41)HttpComponentsAsyncClientHttpResponse:基于Apache HttpComponents HttpAsyncClient的ClientHttpResponse接口的实现类。通过(39)HttpComponentsAsyncClientHttpRequest创建。(Spring 5.0中废弃,无替代者)

(42)HttpComponentsClientHttpRequestFactory:ClientHttpRequestFactory接口的实现类,基于Apache HttpComponents HttpClient创建request。通过createRequest()函数来创建(37)HttpComponentsClientHttpRequest(bufferRequestBody属性为true情况下,属性bufferRequestBody用来表示该工厂是否需要在内部缓存request body,默认为true)或者(38)HttpComponentsStreamingClientHttpRequest(bufferRequestBody属性为false情况下,如果通过POST或者PUT方法发送大量的数据,推荐设置为false,以防止缓存溢出)。

(43)HttpComponentsAsyncClientHttpRequestFactory:继承自HttpComponentsClientHttpRequestFactory,基于Apache HttpComponents HttpAsyncClient 4.0创建(39)HttpComponentsAsyncClientHttpRequest(Spring 5.0中废弃,无替代者)

 

(44)MultipartBodyBuilder:为multipart请求类准备请求体,以MultiValueMap<String, HttpEntity>形式返回。http协议采纳了多部对象集合(multipart),multipart 请求类主要是对文件上传进行的处理,发送一份报文主体内可含有多个类型实体,通常在图片或者文本上传时使用,其中邮件上传各种附件的机制也是用了MIME的Mulipart方法。

(二)http/client/reactive

        reactive programming(响应式编程)是一种异步编程风格,它关注数据流和变化的传播,与之相对应的是imperative programming(命令式编程)。

        在命令式编程中,a:=b+c意味着将b+c的结果赋值给a,并且此后b或c的值发生变化不会影响到a的值。而在响应式编程中,a的值会随着b或c的改变而自动更新,并且不需要重新执行a:=b+c来确定当前分配给a的值。例如,在 model–view–controller (MVC) 架构中,响应式编程可以促进基础模型中的更改,这些更改会自动反映在关联的视图中。

        如果从推拉的角度来看的话,响应式编程是“推”,它主动将变化推送给它的订阅者。Publisher-Subscriber是两个非常重要的概念。本质来讲,响应式编程上是对数据流或某种变化所作出的反应,但是这个变化什么时候发生是未知的,所以他是一种基于异步、回调的方式在处理问题

 

接口

(1)ClientHttpRequest:继承自ReactiveHttpOutputMessage的接口,表示一个客户端的响应式HTTP request请求报文。

(2)ClientHttpResponse:继承自ReactiveHttpInputMessage的接口,表示一个客户端的响应式HTTP response响应报文。

(3)ClientHttpConnector:客户端的HTTP连接器接口,从HTTP客户端抽象出来的一个功能,使HTTP客户端连接到服务器上,也提供了发送ClientHttpRequest和接收ClientHttpResponse所有必要的基础设施。

抽象类

(4)AbstractClientHttpRequest:上述ClientHttpRequest接口实现的抽象类。

装饰器类

(5)ClientHttpRequestDecorator:ClientHttpRequest的装饰器。

(6)ClientHttpResponseDecorator:ClientHttpResponse的装饰器。

 

Jetty ReactiveStreams HTTP client

Jetty 是一个开源的servlet容器,适用于一个通用的Reactive Streams API。

(7)JettyClientHttpRequest:继承自AbstractClientHttpRequest。

(8)JettyClientHttpResponse:ClientHttpResponse接口实现类。

(9)JettyClientHttpConnector:ClientHttpConnector接口实现类。

(10)JettyResourceFactory:在Spring的ApplicationContext容器生命周期范围内,用来管理Jetty资源的工厂,比如Executor、ByteBufferPool、Scheduler。该工厂实现了InitializingBean、DisposableBean接口。一般被声明为Spring管理bean。

 

Reactor-Netty HTTP client

        Netty是一个java开源框架,适用于一个通用的Reactive Streams API。

(11)ReactorClientHttpRequest:继承自AbstractClientHttpRequest、ZeroCopyHttpOutputMessage。

(12)ReactorClientHttpResponse:ClientHttpResponse接口实现类。

(13)ReactorClientHttpConnector:ClientHttpConnector接口实现类。

(14)ReactorResourceFactory:在Spring的ApplicationContext容器生命周期范围内,用来管理Reactor Netty资源的工厂,比如LoopResources、ConnectionProvider。该工厂实现了InitializingBean、DisposableBean接口。一般被声明为Spring管理bean。

(三)http/client/support

(1)HttpAccessor:作为RestTemplate的基类或者其他HTTP访问网关的助手类。定义了一些通用的属性,如ClientHttpRequestFactory。

(2)AsyncHttpAccessor:作为AsyncRestTemplate的基类或者其他HTTP访问网关的助手类。定义了一些通用的属性,如AsyncClientHttpRequestFactory。

(3)InterceptingHttpAccessor:继承自HttpAccessor,增加了一些拦截器相关的属性。

(4)InterceptingAsyncHttpAccessor:继承自AsyncHttpAccessor,增加了请求拦截功能。

 

(5)BasicAuthenticationInterceptor:ClientHttpRequestInterceptor接口的实现类,使用username/password做一个HTTP基本认证,除非的Authorization header设置好了。

(6)BasicAuthorizationInterceptor:ClientHttpRequestInterceptor接口的实现类,使用一个基本的 Authorization 消息头。

 

(7)HttpRequestWrapper:HttpRequest装饰器类。

(8)ProxyFactoryBean:实现ProxyFactoryBean、Initializi

推荐阅读