网络请求(一)— HTTP/0.9、HTTP/1.0、HTTP/2.0、SPDY
1 TCP/IP
概念
TCP/IP
(Transmission Control Protocol/Internet Protocol
,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP
协议不仅仅指的是TCP
和IP
两个协议,而是指一个由FTP
、SMTP
、TCP
、UDP
、IP
等协议构成的协议簇,同时是Internet
最基本的协议、Internet
国际互联网络的基础,由网络层的IP
协议和传输层的TCP
协议组成。TCP/IP
定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。
TCP/IP
的分层管理图:
TCP/IP
协议中最重要的特点就是分层,由上往下分别为应用层,传输层,网络层,数据链路层,物理层:
- 应用层:这一层主要的代表有
DNS
域名解析/HTTP
协议; - 传输层:这一层的功能是使源端主机和目标端主机上的对等实体可以进行会话。在传输层定义了两种服务质量不同的协议,即:传输控制协议
TCP
和用户数据报协议UDP
; - 网络层:是整个
TCP/IP
协议栈的核心。它的功能是把分组发往目标网络或主机。同时,为了尽快地发送分组,可能需要沿不同的路径同时进行分组传递,因此,分组到达的顺序和发送的顺序可能不同,这就需要上层必须对分组进行排序。网络层定义了分组格式和协议,即IP
协议(Internet Protocol
); - 物理层:该层负责比特流在节点之间的传输,即负责物理传输,这一层的协议既与链路有关,也与传输的介质有关。通俗来说就是把计算机连接起来的物理手段;
- 数据链路层:控制网络层与物理层之间的通信,主要功能是保证物理线路上进行可靠的数据传递。为了保证传输,从网络层接收到的数据被分割成特定的可被物理层传输的帧。帧是用来移动数据结构的结构包,它不仅包含原始数据,还包含发送方和接收方的物理地址以及纠错和控制信息,其中的地址确定了帧将发送到何处,而纠错和控制信息则确保帧无差错到达。如果在传达数据时,接收点检测到所传数据中有差错,就要通知发送方重发这一帧;
UDP
和TCP
的特点:
- 用户数据报协议
UDP
(User Datagram Protocol
):无连接,尽最大努力的交付,面向报文,无拥塞控制,支持一对一、一对多、多对一、多对多的交互通信,首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。UDP
是面向报文的传输方式,是应用层交给UDP
多长的报文,UDP
发送多长的报文,即一次发送一个报文。因此,应用程序必须选择合适大小的报文; - 传输控制协议
TCP
(Transmission Control Protocol
):面向连接,每一个TCP
连接只能是点对点的(一对一),提供可靠交付服务,提供全双工通信,面向字节流。应用程序和TCP
的交互是一次一个数据块(大小不等),但TCP
把应用程序看成是一连串的无结构的字节流。TCP
有一个缓冲,当应该程序传送的数据块太长,TCP
就可以把它划分短一些再传送;
UDP
首部格式:
用户数据报有两个字段:数据字段和首部字段,数据字段很简单,只有8
个字节,由4
个字段组成,每个字段的长度都是2
个字节。 各字段意义如下:
- 源端口号:在需要给对方回信时使用,不需要是可全用
0
; - 目的端口号:这在终点交付报文时必须使用;
- 长度:用户数据报
UDP
的长度,最小为8
(仅首部); - 校验和:用于校验用户数据报在传输过程是否出错,出错则丢弃该报文;
TCP
首部格式:
- 源端口和目的端口: 各占
2
个字节,分别写入源端口号和目的端口号; - 序号:占
4
个字节,用于对字节流进行编号,例如序号为301
,表示第一个字节的编号为301
,如果携带的数据长度为100
字节,那么下一个报文段的序号应为401
; - 确认号:占
4
个字节,期望收到的下一个报文段的序号。例如B
正确收到A
发送来的一个报文段,序号为501
,携带的数据长度为200
字节,因此B
期望下一个报文段的序号为701
,B
发送给A
的确认报文段中确认号就为701
; - 数据偏移:占
4
位,指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度; - 确认
ACK
: 当ACK = 1
时确认号字段有效,否则无效。TCP
规定,在连接建立后所有传送的报文段都必须把ACK
置1
; - 同步
SYN
: 在连接建立时用来同步序号。当SYN = 1
,ACK = 0
时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中SYN = 1
,ACK = 1
; - 终止
FIN
: 用来释放一个连接,当FIN = 1
时,表示此报文段的发送方的数据已发送完毕,并要求释放连接; - 窗口:占
2
字节,窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的; - 检验和: 占
2
个字节,检验和字段检验的范围包括首部和数据这两个部分。在计算检验和时,在TCP
报文段的前面加上12
字节的伪首部; - 套接字:
TCP
连接的端点叫做套接字或插口。端口号拼接到IP
地址即构成了套接字;
TCP
的三次握手:
- 首先
Client
端发送连接请求报文; Server
端接受连接后回复ACK
报文(ACK (Acknowledge character)确认字符
),并为这次连接分配资源;Client
端接收到ACK
报文后也向Server
段发生ACK
报文,并分配资源,这样TCP
连接就建立了;
TCP
的四次挥手(中断连接端可以是Client
端,也可以是Server
端):
假设
Client
端发起中断连接请求,也就是发送FIN
报文;Server
端接到FIN
报文后,如果此时还有数据没有发送完成,并不会立刻关闭Socket
,而是继续发送数据。但是可以先发送ACK
,告诉Client
端,请求已收到了,但数据还在发送,请继续等Server
的消息。这个时候Client
端就进入FIN_WAIT
状态,继续等待Server
端的FIN
报文;当
Server
端确定数据已发送完成,则向Client
端发送FIN
报文,表示Sever
端的数据已发送完成,准备好关闭连接了;Client
端收到FIN
报文后,就知道可以关闭连接了,但是担心Server
端不知道要关闭,所以发送ACK
后进入TIME_WAIT
状态,如果Server
端没有收到ACK
则可以重传。Server
端收到ACK
后,就知道可以断开连接了。Client
端等待了2MSL
后依然没有收到回复,则证明Server
端已正常关闭,此时Client
端也可以关闭连接了;
为什么要四次挥手? 客户端发送了FIN
连接释放报文之后,服务器收到了这个报文,就进入了CLOSE - WAIT
状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送FIN
连接释放报文。
什么是HTTP
持久连接? 如果有大量的连接,每次在连接,关闭都要经历三次握手,四次挥手,这显然会造成性能低下。因此,HTTP
有一种叫做长连接(keepalive connections
)的机制。它可以在传输数据后仍保持连接,当客户端需要再次获取数据时,直接使用刚刚空闲下来的连接而无需再次握手。
2 HTTP
和HTTPS
2.1 HTTP/0.9
HTTP
是一种超文本传输协议(Hypertext Transfer Protocol
),是一个基于请求与响应,无状态的,应用层协议,基于TCP/IP
协议传输数据,是最为广泛的一种网络协议,是客户端和服务器端请求和应答的标准(TCP
), 是从WWW
服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTP
的最早版本诞生在1991年,这个最早版本和现在比起来极其简单,没有HTTP
头,没有状态码,没有版本号。后来它的版本号才被定为0.9
,用来和其他版本的HTTP
区分。HTTP/0.9
只支持一种请求方式— GET
,请求只有一行:
GET /hello.html
响应也是非常简单的,只包含html
文档本身:
<HTML>Hello world
</HTML>
当TCP
建立连接之后,服务器向客户端返回HTML
格式的字符串。发送完毕后,就关闭TCP
连接。由于没有状态码和错误代码,如果服务器处理的时候发生错误,只会传回一个特殊的包含问题描述信息的HTML
文件。 这就是最早的HTTP/0.9
版本。
无状态表示客户端没有状态存储,对事物的处理没有“记忆”能力,比如访问一个网站需要反复进行登录操作。
2.2 HTTP/1.0
1996年,HTTP/1.0
版本发布,大大丰富了HTTP
的传输内容,除了文字,还可以发送图片、视频等,这为互联网的发展奠定了基础。相比HTTP/0.9
,HTTP/1.0
主要有如下特性:
- 请求与响应支持
HTTP
头,增加了状态码,响应对象的一开始是一个响应状态行; - 协议版本信息需要随着请求一起发送,支持
HEAD
,POST
方法; - 支持传输
HTML
文件以外其他类型的内容;
一个典型的HTTP/1.0
的请求像这样:
GET /hello.html HTTP/1.0
User-Agent:NCSA_Mosaic/2.0(Windows3.1)200 OK
Date: Tue, 15 Nov 1996 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html<HTML>
一个包含图片的页面
<IMGSRC="/smile.gif">
</HTML>
此时的HTTP
是无连接的,每次请求都要通过TCP
三次握手,四次挥手,和服务端重新建立连接。 比如说某个客户端在短时间内多次请求同一个资源,服务器并不能区别是否之前已经响应过相同的请求,所以每次都用重新响应,耗费不必要的时间和流量。
2.3 HTTP/1.1
在HTTP/1.0
发布几个月后,HTTP/1.1
就发布了。HTTP/1.1
更多的是作为对HTTP/1.0
的完善,在HTTP 1.1
中,主要具有如下改进:
- 可以复用连接;
- 增加
pipeline
:HTTP
管线化是将多个HTTP
请求整批提交的技术,而在传送过程中不需先等待服务端的回应。管线化机制须通过永久连接(persistent connection
)完成。 浏览器将HTTP
请求大批提交可大幅缩短页面的加载时间,特别是在传输延迟(lag/latency
)较高的情况下。有一点需要注意的是,只有幂等的请求可以使用pipeline
,如GET
,HEAD
方法。 - chunked
编码传输:该编码将实体分块传送并逐块标明长度,直到长度为0
块表示传输结束, 这在实体长度未知时特别有用(比如由数据库动态产生的数据);- 引入更多缓存控制机制:如
etag
,cache-control - 引入内容协商机制
,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换; - 请求消息和响应消息都支持
Host
头域:在HTTP 1.0
中认为每台服务器都绑定一个唯一的IP
地址,因此,请求消息中的URL
并没有传递主机名(hostname
)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers
),并且它们共享一个IP
地址。因此,Host
头的引入就很有必要了; - 新增了
OPTIONS
、PUT
、DELETE
、TRACE
、CONNECT
方法;
pipeline [ˈpaɪplaɪn](常指地下的)输送管道
虽然HTTP/1.1
已经优化了很多点,作为一个目前使用最广泛的协议版本,已经能够满足很多网络需求,但是随着网页变得越来越复杂,甚至演变成为独立的应用,HTTP/1.1
逐渐暴露出了一些问题:
- 通信是明文,不加密,不够安全;
- 不验证通信方的身份,可能遭遇伪装请求;
- 无法保护数据的完整性,数据可能遭到篡改;
Header
内容过大,每次请求Header
变化不大,造成浪费;keep-alive
给服务端带来性能压力;
为了解决这些问题,HTTPS
和SPDY
应运而生。
2.4 HTTPS
HTTPS
是以安全为目标的HTTP
通道,简单讲是HTTP
的安全版。HTTPS
的安全基础是SSL
,因此加密的详细内容就需要SSL
。
HTTPS
协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
HTTPS
并非是应用层的一种新协议,只是HTTP
通信接口部分用SSL
(Secure Socket Layer
)和TLS
(Transport Layer Security
)协议代替而已。通常,HTTP
直接和TCP
通信,当使用SSL
时,则演变成先和SSL
通信,再由SSL
和TCP
通信了。
HTTPS
通信方式:
- 客户端使用
HTTPS
的URL
访问服务器端,要求与服务器建立SSL
连接; - 服务器接收到客户端的请求后,会将证书信息(证书中包含公钥)传送一份给客户端;
- 客户端与服务器开始协商
SSL
连接的安全等级,也就是信息加密的等级; - 客户端根据双方同意的安全等级,建立会话密钥,然后利用公钥将会话密钥加密,并传送给服务器;
- 服务器利用自己的私钥解密出会话密钥;
- 服务器利用会话密钥加密和客户端之间的通信;
HTTPS
和HTTP
的区别主要如下:
HTTPS
协议使用ca
申请证书,由于免费证书较少,需要一定费用;HTTP
是明文传输,HTTPS
则是具有安全性的SSL
加密传输协议;HTTP
和HTTPS
使用的是完全不同的连接方式,用的端口也不一样,前者是80
,后者是443
;
SSL
不仅提供加密处理,加密方式为混合加密。而且,SSL
还是用了一种被称为证书的手段,证书是由值得信任的第三方机构颁发,用于证明服务端和客户端是实际存在的(伪造证书是极其困难的)。
2.5 SPDY
其实SPDY
并不是新的一种协议,而是在HTTP
之前做了一层会话层:
在2010年到2015年,谷歌通过实践一个实验性的SPDY
协议,证明了一个在客户端和服务器端交换数据的另类方式。其收集了浏览器和服务器端的开发者的焦点问题,明确了响应数量的增加和解决复杂的数据传输。
在启动SPDY
这个项目时预设的目标是:
- 页面加载时间(
PLT
)减少50%
; - 无需网站作者修改任何内容;
- 将部署复杂性降至最低,无需变更网络基础设施;与开源社区合作开发这个新协议;
- 收集真实性能数据,验证这个实验性协议是否有效;
为了达到降低目标,减少页面加载时间的目标,SPDY
引入了一个新的二进制分帧数据层,以实现多向请求和响应、优先次序、最小化及消除不必要的网络延迟,目的是更有效地利用底层TCP
连接。
2.6 HTTP/2.0
2015年,HTTP/2.0
问世,以下是HTTP/2.0
的特点:
- 使用二进制分帧层:在应用层与传输层之间增加一个二进制分帧层,以此达到在不改动
HTTP
的语义,HTTP
方法、状态码、URI
及首部字段的情况下,突破HTTP1.1
的性能限制,改进传输性能,实现低延迟和高吞吐量。在二进制分帧层上,HTTP2.0
会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码,其中HTTP1.x
的首部信息会被封装到Headers
帧,而我们的request body
则封装到Data
帧里面;
- 多路复用/连接共享:对于
HTTP/1.x
,针对同一域名下的请求有一定数量的限制,超过了限制数目请求会被阻塞。HTTP/2.0
采用了多路复用的方式,允许通过同一个连接发起多重的请求;
- 持久化连接:
HTTP/2.0
都是持久化连接,客户端和服务器之间也只需要一个连接(每个域名一个连接)即可; - 数据流优先级:由于请求可以并发发送了,那么如果出现了浏览器在等待关键的
CSS
或者JS
文件完成对页面的渲染时,服务器却在专注的发送图片资源的情况怎么办呢?HTTP/2.0
对数据流可以设置优先值,这个优先值决定了客户端和服务端处理不同的流采用不同的优先级策略; - 服务端推送:在
HTTP/2.0
中,服务器可以向客户发送请求之外的内容,比如正在请求一个页面时,服务器会把页面相关的logo
,CSS
等文件直接推送到客户端,而不会等到请求来的时候再发送,因为服务器认为客户端会用到这些东西。这相当于在一个HTML
文档内集合了所有的资源; - 头部压缩:使用首部表来跟踪和存储之前发送的键值对,对于相同的内容,不会再每次请求和响应时发送;
HTTP/2.0
的新特点和SPDY
很相似,其实HTTP/2.0
本来就是基于SPDY
设计的,可以说是SPDY
的升级版。 但是HTTP/2.0
仍有和 SPDY
不同的地方,主要有如下两点:
HTTP2.0
支持明文HTTP
传输,而SPDY
强制使用HTTPS
;HTTP2.0
消息头的压缩算法采用HPACK
,而非SPDY
采用的DEFLATE
;
3 Http
的持久连接和HttpClient
连接池
HTTP
协议是无状态的协议,即每一次请求都是互相独立的。因此它的最初实现是,每一个HTTP
请求都会打开一个TCP Socket
连接,当交互完毕后会关闭这个连接。由于HTTP
协议是全双工的协议,所以建立连接与断开连接是要经过三次握手与四次挥手的,在这种设计中,每次发送HTTP
请求都会消耗很多的额外资源,即连接的建立与销毁。
每次建立连接关闭连接都要三次握手、四次挥手,显然会造成效率低下。于是,HTTP
协议的也进行了发展,通过持久连接的方法来进行Socket
连接复用。
从图中可以看到:
- 在串行连接中,每次交互都要打开关闭连接;
- 在持久连接中,第一次交互会打开连接,交互结束后连接并不关闭,下次交互就省去了建立连接的过程;
持久连接的实现有两种:HTTP/1.0+
的keep-alive
与HTTP/1.1
的持久连接。
3.1 HTTP/1.0+
的Keep-Alive
从1996年开始,很多HTTP/1.0
浏览器与服务器都对协议进行了扩展,那就是keep-alive
扩展协议。这个扩展协议是作为HTTP/1.0
的补充的“实验型持久连接”出现的。keep-alive
已经不再使用了,最新的HTTP/1.1
规范中也没有对它进行说明,只是很多应用延续了下来。
使用HTTP/1.0
的客户端在首部中加上Connection:Keep-Alive
,请求服务端将一条连接保持在打开状态。服务端如果愿意将这条连接保持在打开状态,就会在响应中包含同样的首部。如果响应中没有包含Connection:Keep-Alive
首部,则客户端会认为服务端不支持keep-alive
,会在发送完响应报文之后关闭掉当前连接。
通过keep-alive
补充协议,客户端与服务器之间完成了持久连接,然而仍然存在着一些问题:
- 在
HTTP/1.0
中keep-alive
不是标准协议,客户端必须发送Connection:Keep-Alive
来激活keep-alive
连接; - 代理服务器可能无法支持
keep-alive
,因为一些代理是"盲中继",无法理解首部的含义,只是将首部逐跳转发。所以可能造成客户端与服务端都保持了连接,但是代理不接受该连接上的数据;
3.2 HTTP/1.1
的持久连接
HTTP/1.1
采取持久连接的方式替代了Keep-Alive
。HTTP/1.1
的连接默认情况下都是持久连接,如果要显式关闭,需要在报文中加上Connection:Close
首部,即在HTTP/1.1
中,所有的连接都进行了复用。 然而如同Keep-Alive
一样,空闲的持久连接也可以随时被客户端与服务端关闭。不发送Connection:Close
不意味着服务器承诺连接永远保持打开。
HttpClient
如何生成持久连接?HttpClient
中使用了连接池来管理持有连接,同一条TCP
链路上,连接是可以复用的。HttpClient
通过连接池的方式进行连接持久化。
其实“池”技术是一种通用的设计,其设计思想并不复杂:
- 当有第一次连接的时候建立连接;
- 结束时对应连接不关闭,归还到池中;
- 下次同个目的的连接可从池中获取一个可用连接;
- 定期清理过期连接;
参考
https://zhuanlan.zhihu.com/p/49949879
https://www.jb51.net/article/141015.htm
https://zhuanlan.zhihu.com/p/89471776
简单聊下http和https
面试 HTTP ,99% 的面试官都爱问这些问题
万字长文,一文搞懂TCP、IP和HTTP、HTTPS
网络请求(一)— HTTP/0.9、HTTP/1.0、HTTP/2.0、SPDY相关推荐
- 爬虫实战学习笔记_2 网络请求urllib模块+设置请求头+Cookie+模拟登陆
1 urllib模块 1.1 urllib模块简介 Python3中将urib与urllib2模块的功能组合,并且命名为urllib.Python3中的urllib模块中包含多个功能的子模块,具体内容 ...
- 二、Swift网络请求回来的数据我这样取
网络请求框架Alamofire 源码地址 Swift 2.3 Alamofire3.0版本支持 iOS 8 Swift 3 Alamofire4.0以上版本支持 iOS 9及以上系统 json数据: ...
- android retrofit2.0 rxjava2,Android - 网络请求之 Retrofit2 + RxJava
老婆保佑,代码无BUG 目录 引用 与其他开源请求库对比 Retrofit注解 使用 GET请求 POST请求 Retrofit2 + RxJava 基础使用 优化 封装Retrofit2 + RxJ ...
- Android 9.0以上HTTP网络请求被限制解决方案
问题 Android 9.0以上系统,HTTP网络访问请求被限制:但是HTTPS无影响. Android 10系统同样有此问题. 为保证访问安全,Android P以上要求网络请求必须为Https:H ...
- Android 9.0/P(android p指安卓9.0版本) okhttp3网络请求出错
已经在AndroidManifest.xml申请网络权限,在8.0以下的系统中网络访问正常,但是9.0中出现网络请求失败 Android 9.0的网络请求失败如下图: 出现这个错误的原因是:从Andr ...
- Android9.0 http网络请求失败问题分析与解决方案
最近做的项目,在8.0版本以下都是可以正常使用,突然接收到反馈说软件在9.0无法使用,连登陆都无法登陆.而刚好我的手机也刚升级到9.0系统,就进行了测试,发现问题和查找问题,得到以下错误原因和解决方案 ...
- Android9.0以上 http网络请求失败
一.前言 为保证用户数据和设备的安全,Google 针对下一代 Android 系统(Android P) 的应用程序,将要求默认使用加密连接,这意味着 Android P 将禁止 App 使用所有未 ...
- Android9.0 http网络请求失败
解决方法 1.使用HTTPS 2.targetSdkVersion 降到27以下 3.设置isCleartextTrafficPermitted()为false 最近做的项目,在8.0版本以下都是可以 ...
- Android使用Retrofit2.0和RxJava2.0处理网络请求
首先使用SpringBoot创建一个简单的SpringMVC工程. @RestController public class RetrofitController {@RequestMapping(& ...
最新文章
- css中绝对定位中的left和top属性
- 强烈推荐16 款牛逼的 IDEA 插件,让你开发速度飞起来!
- 输入一个数组,逆序存放在另一个数组并输出
- 浅谈Generator和Promise原理及实现
- 聊聊JS与设计模式之(工厂Factory)篇------(麦当劳的故事)
- Binary Tree Inorder Traversal
- 【AngularJS学习笔记】Java Script use strict 严格模式
- SDWebImage原理(面试)
- c语言中精度站的字节,C语言学习--一些细节问题
- 好的程序员“借”,伟大的程序员“偷”!
- 关于 Node 集群
- appinfo.json
- 重建即单体,重建大师5.0发布 模方3.0单体化功能永久免费
- Ubuntu16.04安装搜狗输入法
- 形式语言与自动机 第四章 课后题答案
- Ubuntu 16.04 一系列软件安装命令,包括QQ、搜狗、Chrome、vlc、网易云音乐安装方法
- python实现GIF,PNG,JPG图片转换报错解决
- C64X EDMA优先级及优先级队列
- PPT中如何插入指定大小的矩阵
- 传统安防监控摄像头Onvif云台控制直播流如何转换成GB/T28181对接到国标视频平台公安内网
热门文章
- org.apache.http.conn.HttpHostConnectException: Connection to refused
- ReportEvent的用法
- 开关电源精确到每个元件-分解电源电路
- 各种艺术字体是如何设计的,他们的设计原理有哪些
- [联想]vware打开虚拟机就一直蓝屏关机
- 全军出击机器人进房间_《刺激战场》和《全军出击》快递机器人这么多,你怎么看?...
- 高安全加密BCrypt及其性能缺陷
- Linux文件目录链接方式
- [音乐]歌手萨顶顶及其专辑万物生
- 关于缺少编程基础的朋友想转行 ABAP 开发岗提出的一些咨询问题和解答