目录
HTTP缓存技术
对于有重复性的HTTP请求,每次得到的数据都一样,可以将他们缓存在本地,下次请求直接读取本地数据,不必通过网络获取,这样就可以提高其性能了。
HTTP缓存有两种方式,分别是强制缓存和协商缓存。
强制缓存
强缓存利用HTTP响应头部(Response Header)字段实现,他们都用来表示资源在客户端缓存的有效期:
Cache-Control,是一个相对时间。
Expires,是一个绝对时间。
两个字段都有时,前者优先级更高,前者选项更多设置更精细,建议使用前者。
强制缓存具体实现流程如下:
- 首次请求服务器资源时,服务器返回该资源的同时,通过Response头部的Cache-Control设置过期时间。
- 再次请求该资源时,浏览器会通过请求时间和Cache-Control中的过期时间来判断资源是否过期,如果没有过期,则使用缓存,否则重新请求服务器。
- 当服务器再次接收到请求时,会更新Response头部的Cache-Control信息。
协商缓存
某些请求的响应码是 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
字段,使用这两个字段可以根据资源的唯一标识来确定是否返回新资源或缓存。这两个字段的意思是:
- 响应头部中
Etag
:唯一标识响应资源; - 请求头部中的
If-None-Match
:(当资源过期时,浏览器发现响应头里有 Etag,则再次)向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
因为后者能避免时间篡改导致的问题,所以第二种更可靠。
当首次请求资源时,服务端返回的HTTP响应头部同时有Etag 和 Last-Modified 字段,那么客户端再下次请求时,如带上了 ETag 和 Last-Modified 字段信息给服务端,服务端先会判断 Etag 是否变化了,如果 Etag 有变化就不用在判断 Last-Modified 了,如果 Etag 没有变化,然后再看 Last-Modified,即Etag的优先级更高。
为什么 ETag 的优先级更高?
ETag 的优先级更高是因为它能解决 Last-Modified 难以解决的问题。
1.文件的最后修改时间在没有修改内容的情况下仍可能改变,这会导致客户端错误地认为文件已更改而重新请求。
2.一些文件可能在秒级内频繁修改,而 If-Modified-Since 的粒度只能是秒级,而使用 ETag 可以确保在 1 秒内客户端能够多次刷新。
3.一些服务器无法准确获取文件的最后修改时间。
因此,ETag的优先级高于Last-Modified是因为ETag能够解决Last-Modified存在的问题,包括文件修改时间的误差、频繁修改以及服务器无法获取准确修改时间的情况。
注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
强制缓存和协商缓存的工作流程:
为什么HTTP使用强制缓存和协商缓存同时实现?
HTTP使用强制缓存和协商缓存同时实现是为了兼顾效率和准确性。
强制缓存通过设置过期时间来确定是否使用缓存,可以快速地判断是否需要重新请求资源,提升了请求的响应速度。
而协商缓存通过比较资源的Last-Modified或者ETag来判断资源是否被修改,能够更准确地判断是否需要重新请求资源,避免了由于缓存过期时间不准确或者被篡改导致的不可靠问题。
使用强制缓存和协商缓存的组合可以在保证效率的同时确保缓存的准确性。
当使用 ETag 字段实现的协商缓存的过程:
使用ETag字段实现的协商缓存过程如下:
- 浏览器首次请求服务器资源时,服务器返回资源的同时在Response头部加上ETag唯一标识,该标识是基于当前请求资源生成的。
- 当浏览器再次请求该资源时,首先检查强制缓存是否过期:
- 如果没有过期,则直接使用本地缓存。
- 如果缓存过期,会在Request头部加上If-None-Match字段,该字段的值为ETag唯一标识。
- 服务器收到请求后,会将请求中的If-None-Match值与当前请求资源生成的ETag进行比较:
- 如果值相等,则返回304 Not Modified,不返回资源。
- 如果值不相等,返回200状态码和资源,并在Response头部加上新的ETag唯一标识。
- 浏览器若收到304状态码,则从本地缓存加载资源;否则,更新资源。
HTTP特性
HTTP1.1优点
HTTP最突出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。
-
简单:HTTP的报文格式简单,易于理解和使用,降低了学习和使用的门槛。
-
灵活和易于扩展:HTTP各个组成部分可以自定义和扩充,包括请求方法、URI/URL、状态码、头字段等。同时, HTTP 由于是工作在应用层(
OSI
第七层),则它下层可以随意变化(如HTTPS是在 HTTP 与 TCP 层之间增加了 SSL/TLS 安全传输层,HTTP/1.1 和 HTTP/2.0 传输协议使用的是 TCP 协议,而到了 HTTP/3.0 传输协议改用了 UDP 协议。) -
应用广泛和跨平台:HTTP广泛应用于各个领域,从浏览器到手机应用,从新闻浏览到电子商务等。同时,HTTP天然具有跨平台的特性,可在不同平台上使用和交互。
HTTP1.1缺点
HTTP协议具有优缺点一体的双刃剑,主要包括「无状态」和「明文传输」,同时还存在一个重要缺点,即「不安全」。
-
无状态双刃剑:HTTP协议的无状态特性使服务器不需要记录状态信息,减轻了服务器负担,提高了资源利用率。然而,无状态也带来了一些问题,如在涉及有关联操作时需要重复验证身份信息,降低了用户体验。(针对HTTP的无状态问题,可以使用Cookie技术来维持客户端的状态信息。在客户端第一次请求后,服务器会下发一个装有客户信息的cookie,后续客户端请求服务器的时候,带上cookie,服务器就能认得了了。)
-
明文传输:明文传输是HTTP协议的双刃剑,虽然方便调试和阅读,但也意味着信息的暴露和容易被窃取,增加了安全风险。
-
不安全:不安全是HTTP协议的重要缺点,主要体现在通信使用明文、不验证通信方身份以及无法保证报文完整性,容易遭受窃听、伪装和篡改的攻击。为解决HTTP的安全问题,可以采用HTTPS方式,引入SSL/TLS层,实现通信的加密和身份验证,提高通信的安全性。
HTTP1.1性能
1.长连接
长连接是为了解决HTTP/1.0在性能上的问题而提出的一种通信方式。在HTTP/1.0中,每发起一个请求都需要新建一次TCP连接,增加了通信开销。而长连接允许在一次TCP连接上进行多次请求和响应,减少了TCP连接的重复建立和断开所带来的额外开销,减轻了服务器负载。长连接的特点是只要一端没有明确断开连接,就保持TCP连接状态。当然,如果长连接一段时间内没有数据交互,服务器会主动断开连接。
2.管道网络传输
HTTP/1.1的长连接机制使得管道(pipeline)网络传输成为可能。在同一个TCP连接中,客户端可以同时发起多个请求,无需等待前一个请求的响应返回,从而减少整体的响应时间。然而,服务器必须按照接收请求的顺序发送对这些管道化请求的响应。尽管管道化技术可以解决请求队头阻塞的问题,但无法解决响应队头阻塞的问题。需要注意的是,HTTP/1.1的管道化技术并非默认开启且浏览器大多数不支持。因此,在讨论HTTP/1.1时,一般假定没有使用管道化。
3.队头阻塞
因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是「队头阻塞」,好比上班的路上塞车。