HTTP
一、HTTP发展历程
1900年HTTP/0.9为了便于服务器和客户端处理,采用了纯文本格式,只运行使用GET请求。在响应请求之后会立即关闭连接。
1996年HTTP/1.0增强了0.9版本,引入了 HTTP Header(头部)的概念,传输的数据不再仅限于文本,可以解析图片音乐等,增加了响应状态码和POST,HEAD等请求方法。
1999年广泛使用HTTP/1.1,正式标准,允许持久连接,允许响应数据分块,增加了缓存管理和控制,增加了PUT、DELETE等新的方法。(问题 多个请求并发 管线化 http队头阻塞)
2015年HTTP/2,使用HPACK算法压缩头部,减少数据传输量。允许服务器主动向客户端推送数据,二进制协议可发起多个请求,使用时需要对请求加密通信。(多路复用 1条tcp链接 来通信数据)
2018年HTTP/3基于UDP的QUIC协议。
二、HTTP/1.1(纯文本协议 安全问题 明文 )
基于tcp传输层,所以tcp的问题依然存在。半双工通信,请求应答模式。http默认是无状态(默认tcp不能再没有应答完成后复用tcp通道继续发送消息)
- HTTP/1.1是可靠传输模式,基于
TCP/IP协议 - 采用应答模式,客户端主动发起请求,服务器被动回复请求;
- HTTP是无状态的每个请求都是互相独立
- HTTP协议的请求报文和响应报文的结构基本相同,由三部分组成。
1.内容协商
客户端和服务端进行协商,返回对应结果
| 客户端Header | 服务端Header | |
|---|---|---|
| Accept | Content-Type | 我发给你的数据是什么类型 |
| Accept-encoding | Content-Encoding | 我发给你的数据是用什么格式压缩(gzip、deflate、br) |
| Accept-language | 根据客户端支持的语言返回(多语言) | |
| Range | Content-Range | 范围请求数据 |
2.长连接
HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无谓的 TCP 连接建立和断开,增加了通信开销。
TCP的连接和关闭非常耗时间,所以我们可以复用TCP创建的连接,HTTP/1.1响应中默认会增加Connection:keep-alive(必须在一次请求应答后才能复用)
3.管线化
如果只创建一条TCP连接来进行数据的收发,就会变成”串行“模式,如果某个请求过慢就会发生阻塞问题。Head-ofline blocking,Http/1.1中采用了管线化的方式,对一个域名同时发起多个长连接实现并发。默认chrome为6个。
问题在于虽然请求是并发的,但是响应依旧是按顺序的 (管道的特点就是先发送的先回来)(队头阻塞 HTTP1.1中的队头阻塞)
因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是「队头阻塞」,好比上班的路上塞车。
4.Cookie
Set-Cookie/Cookie用户第一次访问服务器的时候,服务器会写入身份标识,下次再请求的时候会携带cookie。通过Cookie可以实现有状态的会话。
5. HTTP 缓存
HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
-
强制缓存
-
当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在
Response头部加上Cache-Control,Cache-Control中设置了过期时间的大小。 -
浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与Cache-Control中设置的过期时间大小,来计算出该资源是否过期,如果没有过期,则使用该缓存,否则重新请求服务器。
-
服务器再次收到请求后,会再次更新
Response头部的Cache-Control -
Cache-Control, 是一个相对时间; -
Expires,是一个绝对时间; -
强制缓存存在有效期,缓存器内不会向服务器发送请求。超过时间后需要去服务端验证是否是最新版本。
-
-
协商缓存
-
当强制缓存失效后,会再次向服务器发起请求,服务器需要比对客户端的缓存的文件和服务端是否一致,如果一致则返回
304状态码。如果文件更新了,那么就采用返回新文件的方式。 -
第一种:请求头部中的
If-Modified-Since字段与响应头部中的Last-Modified字段实现,这两个字段的意思是:- 响应头部中的
Last-Modified:标示这个响应资源的最后修改时间; - 请求头部中的
If-Modified-Since:当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
第二种:请求头部中的
If-None-Match字段与响应头部中的ETag字段,这两个字段的意思是:- 摘要算法(md5): 不同的内容摘要的结果肯定不同,长度是相同,结果会产生剧烈变化,两个相同的内容摘要的结果肯定是相同,无法通过最终的结果反推原内容。缺点:文件过大,做摘要非常消耗性能,会简单使用弱指纹,可以用
last-modified+ 文件长度,成为一个指纹。 - 响应头部中
Etag:唯一标识响应资源; - 请求头部中的
If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者更加准确。若是服务端返回的
响应头中同时有Etag和Last-Modified字段,这时,Etag的优先级更高。注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
- 响应头部中的
-