所谓“协商”,可以理解为:客户端和服务端双方商量着来。
客户端检查资源超过有效期、强缓存命中失败的情况下,则发出请求“询问”服务器是否资源真的过期了,询问的同时在请求头要携带着资源的「上次更新时间」或者「唯一实体标识」(不同http版本导致的共存问题)。
服务端核对客户端要请求的资源的「上次更新时间」或者「唯一实体标识」:
概括如下图:
协商缓存就是缓存验证。
只有在服务器返回强校验器或者弱校验器时才会进行验证。
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。 服务器接 收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。 协商缓存中,就有很多这样的附带条件请求。
《图解HTTP》
该状态码虽然是3XX的类别,但是跟301、302不一样,不是重定向的含义。 304,Not Modified。表示服务端资源未改变,可直接使用客户端缓存过的、未过期的资源。
1、客户端采用GET方法,且在请求报文中含有“If-Match”、“If-Modified-Since”、“If-None-Match”、“If-Range”、“If-Unmodified-Since”等字段 2、服务器端接收到请求,允许请求并访问资源。但因客户端的请求未满足条件,就直接返回了304。
304状态码返回时,不包含任何响应的主体部分。 也就是说,如果命中协商缓存,服务端响应请求时,只会返回一个304状态码、并没有实际上的文件内容,因此在响应体体积上的节省是协商缓存的优化点
实体首部字段:Last-Modified,表示资源最后被修改的时间。
格式如:
last-modified: Thu, 01 Jan 1970 00:00:00 GMT
这句话就像是服务器告诉客户端,你请求的这个文件是1970年1月1日修改的。
Last-Modified是一种缓存弱校验器。说它弱是因为它只能精确到一秒。
如果响应头里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存:
请求首部字段
他是与Last-Modified对应的字段,存储的是上次缓存的资源最终更新时间,也就是上次缓存资源时获取的Last-Modified的值。
用于确认代理服务器/客户端拥有的本地资源的有效性。 如果在If-Modified-Since字段指定的日期时间后,资源发生了改变,服务器会接受请求。
上图中,服务端拿着他的值和服务端本地被请求资源的Last-Modified进行比较:
他的格式如:
if-modified-since: Thu, 01 Jan 1970 00:00:00 GMT
响应首部字段,缓存的一种强校验器。
实体标记(Etag)是与特定资源关联的特定值,是资源唯一性标识的字符串。服务器会为每份资源分配对应的 ETag 值。 并通过响应头首部字段告知客户端资源的实体标识。
格式如:
etag: f7b80870fbcd8f9da18ab22d2ef1932c
ETag 中有强 ETag 值和弱 ETag 值之分。
强 ETag 值,不论实体发生多么细微的变化都会改变其值。
ETag: "usagi-1234"
弱 ETag 值只用于提示资源是否相同。只有资源发生了根本改变,产 生差异时才会改变 ETag 值。
这时,会在字段值最开始处附加 “W/”。如下:
ETag: W/"usagi-1234"
请求首部字段
他是与Etag对应的字段,存储的是上次缓存的资源的实体标记值,也就是上次缓存资源时获取的Etag的值。
协商缓存时,客户端携带该字段与服务端资源的Etag字段值进行比对,只有在If-None-Match的字段值与Etag值匹配不上、不一致时,命中协商缓存。
在GET或HEAD请求方法中,使用If-None-Match可获取最新的资源。
格式如:
if-none-match: f7b80870fbcd8f9da18ab22d2ef1932c
他和If-Match的作用相反。
用法和规则基本同If-None-Match,但判断逻辑完全相反。
If-Match的这个条件的判断逻辑是:只有当 If-Match 的字段值跟 ETag 值匹配一致时才会命中协商缓存。服务器才会接受请求 并返回200和新数据。 反之,服务器返回状态码 412 Precondition Failed 的响应。
还可以使用 星号(*) 指定 If-Match 的字段值。
针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。
if-match: f7b80870fbcd8f9da18ab22d2ef1932c
或者
if-match: *
首先,Etag的优先级高于Last-Modified。
Last-Modified和Etag的优缺点分析如下:
不存在版本问题,每次请求都会去服务器进行校验。服务器对比最后修改的时间,如果相同返回 304,不同的话返回 200 以及相应的数据资源
最后再整体回顾、复习一下子。
(注意:实际HTTP1.1的请求中,两组字段同时包含在请求及响应头中,我这里为了加深组CP的印象,分开阐述)
浏览器在发起请求时,服务器在响应头中返回请求资源的唯一标识。在下一次请求时,会将上一次返回的 Etag 值赋值给 If-None-match 并添加在响应头中。服务器将浏览器传来的 if-no-matched 跟自己的本地的资源的 Etag 做对比,如果匹配,则返回 304 通知浏览器读取本地缓存,否则返回 200 和更新后的资源。