资源验证Last-Modified、Etag
为了配合Cache-Control中no-cache,在server端我们还需要加上头Last-Modified、Etag。收到带Last-Modified这个头,下次浏览器发送request就会带上If-Modified-Since或者If-Unmodified-Since,服务器收到这个request的If-Modified-Since后,通过读取它的值对比资源存在的地方的Last-Modified,服务器就告诉浏览器是否可以使用缓存。Etag是一个更加严格的验证,它是根据文件的内容生成Etag(数据签名,最常用做法是对资源内容进行哈希计算),收到带Etag这个头,下次浏览器发送request就会带上If-Match或者If-Non-Match,服务器收到这个request的上If-Match或者If-Non-Match后,通过读取它的值对比资源存在的地方的Etag,服务器就告诉浏览器是否可以使用缓存。
上面说的很啰嗦,下面用简单例子来说明(接着上一篇Cache-Control):给response header加上头Last-Modified、Etag。
server.js启动node server.js,打开network如下:
重新刷新浏览器,打开network如下:
对比上面两张network截图,发现下面再次发送请求,Request Header已经带上了If-Modified-Since(对应Last-Modified)和If-None-Match(对应Etag),后面每次发送相同url请求都会带上If-Modified-Since和If-None-Match,server端拿到这两个值与自身的进行比较。
修改server.js如下:
server.js首次打开页面network如下:
再次刷新页面后,打开network如下:
上面的两个截图是再次刷新得到的,首先由于etag与之前比较没有发生变化,所以返回304,同时我们在代码中没有返回任何内容,response.end('')。可是我们在response仍然看见了response,这是浏览器命中缓存然后放进去的。
此时我修改script.js中的内容和加上response.end('1234567890'),而不是之前的response.end(''),重启服务,打开network,看见的仍然是:
可以看出浏览器没有获取新的内容,而是仍然命中缓存。
但是此时如果我将返回码304,改成200。server.js改变如下:
server.js此时浏览器始终返回200,并且浏览器network始终如下:
所以浏览器是通过返回码304(Not Modified),来判断是否命中缓存,还是去更新。当然304才是http规范的返回码,我们应该杜绝资源验证通过后,还是返回200。
如果我们只去掉no-cache,则network如下:
可见,去掉no-cache则始终返回200,而且将始终直接从缓存中读取,不经过任何网络传输。与之对应的头,Last-Modified和Etag将被忽略(下次请求request headers没有带上If-Modified-Since和If-None-Match)。
另一种情况:恢复no-cache的设置,然后勾上浏览器的Disable cache,则也始终返回200,忽略相应的头,始终重新去取。
最后一种情况:将no-cache改成no-store,不勾选浏览器的Disable cache,则达到与勾选一样的效果。两幅图和上面一样,这里不再附上。
本文大致说了http的处理细节,至于将Last-Modified和Etag具体设置为何值,和如何在服务端比较它们和客户端传过来的If-Modified-Since和If-none-Match比较,这个更多涉及服务端的实现。所以这里没有深入研究。