浏览器缓存
浏览器缓存
之前在面试的时候被问到过关于缓存的事情今天想起来可以总结一下
缓存是可以分为两种 分别是协商缓存和强缓存,强缓存是不经过服务器的
但是协商缓存是需要经过服务器,协商缓存返回的状态码是304
这两类缓存机制是可以同时存在的 , 强缓存的优先级要高于协商缓存
当执行强缓存时,如果缓存命中,则直接使用缓存数据库中的数据,如果没有在进行协商缓存
强缓存
Expires(HTTP1.0): Exprires的值为服务端返回的数据到期时间.当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据.但是由于服务端时间和客户端时间有可能存在误差,这样将导致缓存命中的误差.另一方面,Expires是HTTP1.0的产物,故现在大多数使用Cache-Control代替.
缺点: 强缓存使用的是绝对的时间,如果服务端和客户端的时间产生偏差那么会导致命中缓存存在偏差
Pragma(HTTP1.0): HTTP1.0时遗留下来的字段,当值为"on-cache"时强制验证缓存,Pragma
禁用缓存,如果又给Expires定义一个还未到期的时间,那么Pragma字段的优先级会更高.服务端响应添加"Pragma":"no-cache",浏览器的表现行为和刷新(f5)类似
Cache-Control(HTTP1.1): 有很多属性,不同的属性代表的意义也不同:
属性 | 功能 |
---|---|
private | 客户端可以缓存 |
public | 客户端和代理服务器都可以缓存 |
max-age=t | 缓存内容在t秒后失效 |
no-cache | 需要使用协商缓存来验证数据 |
no-store | 所有内容都不会缓存 |
这里注意的是no-cache
指令很多人误以为是不缓存,这是不准确的,no-cache
的意思是可以缓存,但是每次用应该是向服务器验证缓存是否可用. no-store
才是不缓存内容. 当在首部的字段Cache-Control
有指定max-age
指令时,比起首部字段Expires
,会优先处理max-age
指令.
命中强缓存的表现形式为:
火狐:灰色的200状态码
谷歌:200(from disk cache) 或者 200 ok (feom memory cache)
协商缓存
协商缓存是需要进行对比判断是否可以使用缓存.浏览器第一次请求时,服务器会将缓存标识与数据一起响应给客户端,客户端将他们分别备份至缓存中,再次请求的时候,客户端会将缓存中的标识发送给服务端,服务端根据标识判断.若没有失效,返回304,浏览器拿到此状态码就可以直接使用缓存数据
Last-Modified: 服务器在响应请求时,会告诉浏览器资源最后的修改时间
if-Modified-Since: 浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获取得最后修改时间,服务端收到此请求头发现有if-Modified-Since
,则与被请求资源的最后修改时间进行对比,如果一至则返回304和响应报文头,浏览器只需要从缓存中获取信息即可
如果真的被修改:那么开始传输相应一个整体,服务器返回:200 ok
如果没有被修改:那么只需要传输相应header,服务器返回:304 not modified
if-Unmodified-Since: 从某个时间点算起, 是否文件没有被修改,使用的是相对时间,不需要关心客户端和服务端的时间偏差。
如果没有被修改:则开始`继续'传送文件,服务器返回: 200 OK
如果文件被修改:则不传输,服务器返回: 412 Precondition failed (预处理错误)
这两个的区别是一个是修改了才下载一个是没修改才下载。如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP1.1推出了Etag。
Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)
If-Match:条件请求,携带上一次请求中资源的ETag,服务器根据这个字段判断文件是否有新的修改
If-None-Match:再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。服务器接收到次报文后发现If-None-Match则与被请求资源的唯一标识进行对比。
不同,说明资源被改动过,则响应整个资源内容,返回状态码200。
相同,说明资源无新修改,则响应header,浏览器直接从缓存中获取数据信息。返回状态码304.
但是实际应用中由于Etag的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用Etag了。
浏览器地址栏中写入URL,回车浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿(最快)
F5就是告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就会发送一个请求带上If-Modify-since
Ctrl+F5告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服
务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作
缓存场景
对于大部分的场景都可以使用强缓存配合协商缓存解决,但是在一些特殊的地方可能需要选择特殊的缓存策略
对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存
对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新
对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文
件