HTTP实用指南
HTTP协议分析
请求方式:Method
safe安全请求
使用GET、HEAD、OPTIONS请求是安全的,不会修改服务器的数据。
Idempotent幂等请求
同样的请求被执行一次和连续执行多次的效果是一样的,服务器的状态也是一样的。所有的safe请求方法都是幂等的。
幂等请求有:GET、HEAD、OPTIONS、PUT、DELETE。
状态码
常用的请求头
常用的响应头
缓存
什么是缓存
缓存就是一个资源副本。当我们向服务器请求资源后,会根据情况将资源 copy 一份副本存在本地,以方便下次读取。它与本地存储 localStorage
、cookie
等不同,本地存储更多是数据记录,存储量较小,为了本地操作方便。而缓存更多是为了减少资源请求,多用于存储文件,存储量相对较大。
缓存的作用
缓存最根本的作用就是减少没必要请求。有些资源,比如用户头像图片,很久才改变一次,但每次都要去请求这张一样的图片,通信一来一回增加了页面的显示时长,过多没必要请求也增加了服务器的压力。如果把这张图片直接缓存在本地,那每次就可以直接本地读取加载,不再发起请求。所以缓存的好处也就显而易见了,减少了时长从而优化用户体验,也减少了流量消耗,减轻了服务器的压力。
强缓存
直接从本地副本比对读取,不去请求服务器,返回的状态码是 200。主要包括 expires
和 cache-control
。
expires
expires
是 HTTP1.0
中定义的缓存字段。当我们请求一个资源,服务器返回时,可以在 Response Headers
中增加 expires
字段表示资源的过期时间。
它是一个时间戳,当客户端再次请求该资源的时候,会把客户端时间与该时间戳进行对比,如果大于该时间戳则已过期,否则直接使用该缓存资源。
但是,有个大问题,发送请求时是使用的客户端时间去对比。一是客户端和服务端时间可能快慢不一致,另一方面是客户端的时间是可以自行修改的(比如浏览器是跟随系统时间的,修改系统时间会影响到),所以不一定满足预期。
cache-control
正由于上面说的可能存在的问题,HTTP1.1
新增了 cache-control
字段来解决该问题,所以当 cache-control
和 expires
都存在时,cache-control
优先级更高。该字段是一个时间长度,单位秒,表示该资源过了多少秒后失效。当客户端请求资源的时候,发现该资源还在有效时间内则使用该缓存,它不依赖客户端时间。cache-control
主要有 max-age
和 s-maxage
、public
和 private
、no-cache
和 no-store
等值。
max-age和s-maxage
两者是 cache-control
的主要字段,它们是一个数字,表示资源过了多少秒之后变为无效。在浏览器中,max-age
和 s-maxage
都起作用,而且 s-maxage
的优先级高于 max-age
。在代理服务器中,只有 s-maxage
起作用。 可以通过设置 max-age
为 0 表示立马过期来向服务器请求资源。
public和private
public
表示该资源可以被所有客户端和代理服务器缓存,而 private
表示该资源仅能客户端缓存。默认值是 private
,当设置了 s-maxage
的时候表示允许代理服务器缓存,相当于 public
。
no-cache和no-store
no-cache
表示的是不直接询问浏览器缓存情况,而是去向服务器验证当前资源是否更新(即协商缓存)。no-store
则更狠,完全不使用缓存策略,不缓存请求或响应的任何内容,直接向服务器请求最新。由于两者都不考虑缓存情况而是直接与服务器交互,所以当 no-cache
和 no-store
存在时会直接忽略 max-age
等。
协商缓存
会去服务器比对,若没改变才直接读取本地缓存,返回的状态码是 304。
如果设置了 no-cache
和 no-store
则本地缓存会被忽略,会去请求服务器验证资源是否更新,如果没更新才继续使用本地缓存,此时返回的是 304,这就是协商缓存。协商缓存主要包括 last-modified
和 etag
。
last-modified
last-modified
记录资源最后修改的时间。启用后,请求资源之后的响应头会增加一个 last-modified
字段,如下:
last-modified: Thu, 20 Dec 2018 11:36:00 GMT
当再次请求该资源时,请求头中会带有 if-modified-since
字段,值是之前返回的 last-modified
的值,如:if-modified-since:Thu, 20 Dec 2018 11:36:00 GMT
。服务端会对比该字段和资源的最后修改时间,若一致则证明没有被修改,告知浏览器可直接使用缓存并返回 304;若不一致则直接返回修改后的资源,并修改 last-modified
为新的值。
使用last-modified
有以下两个缺点:
- 只要编辑了,不管内容是否真的有改变,都会以这最后修改的时间作为判断依据,当成新资源返回,从而导致了没必要的请求响应,而这违背了缓存本来的作用即避免没必要的请求。
- 时间的精确度只能到秒,如果在一秒内的修改是检测不到更新的,仍会告知浏览器使用旧的缓存。
etag
etag
会基于资源的内容编码生成一串唯一的标识字符串,只要内容不同,就会生成不同的 etag
。启用 etag
之后,请求资源后的响应返回会增加一个 etag
字段,如下:
etag: "FllOiaIvA1f-ftHGziLgMIMVkVw_"
当再次请求该资源时,请求头会带有 if-none-match
字段,值是之前返回的 etag
值,如:if-none-match:"FllOiaIvA1f-ftHGziLgMIMVkVw_"
。服务端会根据该资源当前的内容生成对应的标识字符串和该字段进行对比,若一致则代表未改变可直接使用本地缓存并返回 304;若不一致则返回新的资源(状态码200)并修改返回的 etag
字段为新的值。
etag的缺点就是每次生成标识字符串会增加服务器的开销。