持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
协商缓存
若未命中强缓存(强缓存过期了),则浏览器会将请求发送至服务器。服务器根据http头信息中的Last-Modify/If-Modify-Since或Etag/If-None-Match来判断是否命中协商缓存。如果命中,则http返回码为304(你本地之前加载的资源是有效的),浏览器从缓存中加载资源。
Last-Modify/If-Modify-Since
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify.是一个时间标识该资源的最后修改时间,例如Last-Modify:Thu,31Dec203723:59:59GMT。
当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Sincel后,根据资源的最后修改时间判断是否命中缓存。
如果命中缓存,则返回http,并且不会返回资源内容,并且不会返回Last-Modify。
由于对比的是服务端时间,所以客户端与服务端时间差距不会导致问题。但是有时候通过最后修改时间来判断资源是否修改还是不太准确(资源变化了最后修改时间也可以一致)。最后修改只能精确到秒级,于是出现了ETag/If-None-Match。
ETag/If-None-Match
与Last-Modify/If-Modify-Since(最后修改时间)不同的是,Etag/If-None-Match返回的是一个校验码(ETag:entity tag)。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。ETag值的变更则说明资源状态已经被修改。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?
HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
1.Last-Modified标注的最后修改只能精确到秒级。如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间。
2.如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存。
3.有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。不会仅仅只根据时间判断是否进行使用缓存。
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。
强缓存:大大的减少了服务器的请求次数,在过期时间内,直接从客户端内存中读。
协商缓存:强缓存命中失效了,超过过期时间了,拿着标识(最后的修改时间,唯一标识etag),去问服务器,是否真的过期了。如果验证通过,服务器会直接响应304,且不会返回资源。