软件使用者通常会在客户端版本落后于服务器最新版本时才会去服务器获取新的软件。
这一理念也用于了浏览器缓存策略中。结合下面这张图为例,浏览器已经缓存了 foo.jpg 且已记录版本号为1.2 (这个版本号由服务器生成并告诉浏览器),那么当浏览器再次请求 foo.jpg 时,就会同时把版本号也放在请求头中。这样,服务器收到请求时,就知道了客户端已缓存的文件的版本。如果服务器中的 foo.jpg 版本也是 1.2,那么服务器就可以说 304 Not Modified,不用再将 foo.jpg 传给了浏览器,因此就节省了带宽。反之,如果服务器端的 foo.jpg 已经 1.3 了,那么就要将新的文件传给浏览器,也同时告诉它版本号为 1.3,浏览器收到后,缓存文件,并记录版本号为 1.3。
ETag 是 Response Header 中的一个字段,而与之对应的一个出现在请求头中的字段为 If-None-Match。If-None-Match 对应的值即为浏览器缓存的的文件的版本号。
这次我们把它标记为 foobar。注意版本号并不一定要像软件开发的版本号具有语义化,相反它可以是任意字符串,只要确保两个版本间的版本号不一样就行。
刷新页面继续请求:
可以发现,这次请求头中多了 if-none-match 字段,其值就是 foobar。因此这次 foobar 和服务器版本相同,因此可以直接返回 304。
如果,修改本地服务器版本号,比如改成 package:
再次请求,
如图,这次因为版本号不同了,所以服务端要再次发送文件,并且通知浏览器更新版本号。
源码中有这么几行代码:
它的意思其实就是将文件的 md5 值作为版本号,因为文件内容一旦改变,那么它的 md5 也一定随之改变。