Http知识全梳理

303 阅读7分钟

一 HTTP 发展演变过程

1.HTTP 0.9 1991

1991年开始启用http协议,在当时人们的需求只是浏览网页,找到自己需要的信息,所以设计上只使用了get命令,此时规定服务器只能回应HTML格式的字符串,服务器发送完就会关闭TCP连接

2.HTTP 1.0 1996

在这一阶段,首先可以传递各种格式的内容(文字,图片,视频等等),还引入了POST命令和HEAD命令。此外,Http的请求和回应格式也变了,除了数据部分,还引入了请求头Header
其他的还包括如状态码,多字符集支持,多部分发送,权限(authorization),缓存,内容编码,部分字段会在后面部分介绍
Http 1.0有一个缺点,每个TCP连接只能发送一个请求,发送数据完毕后,连接就关闭。这无疑很浪费资源,因为我们知道,每一个TCP连接都伴随着三次握手四次回收。有一个解决办法是使用Connection:keep-alive字段
当请求的时候加入
Connection:keep-alive
服务器同样返回
Connection:keep-alive
这样就能保持持久连接了 但是这个并没有被列入标准。直到Http 1.1到来

3.HTTP 1.1 1997

Http 1.1进一步完善了协议,并且一直保持使用了20年,直到Http2.0的发布。Http 1.1有哪些变化呢

3.1 持久连接

刚刚说到1.0的版本缺点,以及keep-alive的使用,1.1则正式改变了。1.1默认连接不关闭,可以被多个请求复用。使用了一个字段Connection。目前对于同一个域名,浏览器最多允许同时建立6个持久连接

3.2 管道机制

在持久连接的基础上,一个TCP虽然可以发送多个请求,但是服务端的响应是按照请求的先后顺序来回应发送的。举个例子,客户端三个请求ABC虽然可以同时并发请求资源,但是服务端响应的数据一定是A请求处理好回应了之后再依次回应BC请求。显然这是一个可以改善的地方

3.3 其他

其他的新增内容有请求方法的扩充,分块传输编码,有兴趣的可以再了解一下,本文不再细说

3.4 缺点

显然是管道机制带来的问题,这被称为队头堵塞

4.HTTP 2.0

HTTP 2.0是在2009年谷歌的SPDY协议的基础上设计的,发布于2015年。特点如下

4.1 二进制协议

2.0之前头信息是ASCII码,数据部分可以是ASCII编码/二进制。在2.0中会只用二进制,并将其成为帧(frame)

4.2 数据流

HTTP 2.0中将每个请求或回应成为一个数据流,每个数据流有一个独一无二的编号,数据包发送时都必须标记数据流ID,用来加以区分,客户端为奇数,服务端为偶数

4.3 多路复用

这个就解决了1.1的队头阻塞问题,具体来说,就是允许在一个TCP连接中客户端和服务器多次发送请求和回应请求。由于引入二进制数据,可以对二进制数据流进行标示,服务器并行回应请求后可以通过标示按照请求顺序重新组装报文。

4.4 服务器推送

HTTP 2.0允许服务器主动向客户端发送资源

4.5 头信息压缩

由于HTTP协议无状态,所以需要附带很多头部信息。这就导致很多信息重复发送,浪费带宽,也影响速度。HTTP 2.0中,头信息会使用gzip或者compress压缩后发送,另一方面,客户端和服务端都会维护一张表,所有字段存入这个表中,每个字段有对应的索引号,这样只用发索引号就能提高速度了

二 HTTP的报文结构

无论是请求报文还是响应报文,我们都能发现HTTP的结构如此:起始行+头部+空行+实体 下面分别介绍

1.起始行

起始行由 请求方法+请求URL+HTTP协议及版本构成 例如
get /home http1.1

2.头部

头部字段很多,也涉及很多HTTP特性,部分内容会在后面进行介绍,这里笔者准备先总体粗略的介绍一下常见的字段

2.1 通用首部字段

Date
Cache-Control 缓存相关
Connection 持久连接

2.2 请求首部字段

Accept
If-Match
If-None-match
If-Modified-Since
Authorization

2.3 响应首部字段

ETag

2.4 实体头部字段

Content-Type
Last-Modified
Expires

三 部分HTTP字段详解

1.关于缓存的字段

缓存有很多种,数据库缓存/服务器缓存/CDN缓存/浏览器缓存等等。这里介绍的是浏览器缓存相关的内容。
浏览器缓存位置又分为Service Worker/Memory Cache/Disk Cache/Push Cache四个位置 具体的区别这里也暂时不想深入展开了。下面直接说缓存的字段

1.1 强缓存相关的Cache-control/Expires

在第一次访问服务器的时候,肯定是和强缓存没关系的,但是后面当服务器返回数据后会将相关的头字段(缓存标识)存入上文提到的四个缓存位置中的某一处,再下一次请求数据时,就会去缓存位置中寻找缓存标识,找到了,就会启动强缓存策略,不用发送请求,数据直接从缓存读,返回的状态吗200.相关字段如下

Expires:用来规定资源的到期时间
Cache-control 里面有以下的几个常见字段:
public:表示响应可以被客户端和代理服务器缓存
private:表示响应只能被客户端缓存,代理服务器不缓存
max-age:设置缓存的有效时间
no-cache:可以在客户端/代理服务器缓存,但是缓存需要服务器验证
no-store:不会缓存任何东西,每次都需要从服务器获取

1.2 协商缓存相关的 Last-Modified/If-Modified-Since ETag/If-None-Match

当强缓存失效后,浏览器携带协商缓存相关的标识向服务器发送请求,由服务器根据缓存标示来决定是否决定启动协商缓存策略
Last-Modified/If-Modified-Since:在第一次访问服务器请求资源之后,服务器会在response Header添加Last-Modified相关信息,再次访问的时候,在If-Modified—Since中添加这些信息,服务器根据这个信息进行对比发现资源和上次请求的有没有变化。没有则返回状态码304,启动协商缓存策略
ETag/If-None-Match:这两个字段是解决Last-Modified/If-Modified-Since在毫秒级别改变无法捕捉到的情况。ETag是由文件内容生成唯一标识。第一次访问时,服务器会在响应头中添加生成的ETag值并存入相应的缓存位置中,下次访问时在If-None-Match中添加这个值,由服务器判断是否改变,没有则返回304采用协商缓存策略。

2.Content-Type字段

content-type用于指定资源的MIME类型,即告诉客户端回送的数据格式是什么其格式由 text/html+charset+boundary构成
其中text/html是指请求的media-type,又由type和subtype组成,以/分割,而type和subtype各自还有不同的类型,这里笔者由于没有详细了解也不再一一列举
charset则顾名思义,代表指定字符串的编码标准,例如UTF-8,ASCII等等
boundary则用于上传文件时,分割数据时使用
下面列举一些常见的content-type

2.1 application/x-www-form-urlencoded

这是比较常见表单提交格式,它会要求例如
{a:1, b:2}形式的数据转换成a=1&b=2形式发送

2.2 application/json

这个字段要求你的请求体中的数据是JSON格式的数据(即对象的键值和键名都是字符串形式)

2.3 multipart/form-data

multipart/form-data是使用POST请求上传文件,如果上传照片,文件等,由于很多情况下都会有批量上传,为了区分不同的数据,multipart/form-data的类型有boundary参数进行分割,对上传文件请求抓包