http缓存
- 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
- 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中
强缓存
- Expire(http1.0) 服务其返回该请求结果缓存的到期时间
Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效 - Cache-Control(http1.1)
public:所有内容都将被缓存(客户端和代理服务器都可缓存)
private:所有内容只有客户端可以缓存,Cache-Control的默认取值
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
eg:
- 状态码为200 不会访问服务器,所以就算文件改了
res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toGMTString()); // 绝对时间 (服务器告诉一个时间,客户端请求时判断当前时间是否超过服务器给的时间,超过则重新获取资源;弊端:服务器和客户端时间可能不同)
res.setHeader('Cache-Control', 'max-age=10')// 相对时间
- 直接访问的资源会自动设置Cache-Control: max-age=0;默认访问的资源(favicon.ico)不走强制缓存
- res.setHeader(‘Cache-Control’, ‘no-cache’) 走协商缓存
- res.setHeader(‘Cache-Control’, ‘no-store’) 不走缓存(协商缓存、强缓存均失效)
协商缓存 (协商缓存生效,返回304)
- Last-Modified/If-Modified-Since
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间 - Etag/If-None-Match
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)
If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。
eg:
- 浏览器看到状态码为304后就会自己去找缓存
-
last-modified/if-modified-since(缺点:修改了文件,但是文件没有变化,缓存也会失效;文件的最后修改时间是以秒为单位的,如果一秒内修改了n次,是无法比对的)
const lastModified = statObj.ctime.toGMTString() const ifModifiedSince = req.headers['if-modified-since'] res.setHeader('Last-Modified', lastModified) if (ifModifiedSince === lastModified) { res.statusCode = 304 res.end() }else{ console.log('重新读取资源文件返回') }
-
etag/if-none-matched(一般认为etag优先级高于last-modified,代码可以控制优先级)
- 使用md5
- md5是一种摘要算法,同一个文件摘要出的结果相同,如果内容有一点变化,摘要后的结果会发生剧烈变化
- md5是不可逆的
- 不同内容摘要后的结果长度相同
// 需要读取文件,性能太差。。 const etag = crypto.createHash('md5').update(readFileSync(originalPath)).digest('base64') // 读取文件生成etag let ifNoneMatch = req.headers['if-none-match']; res.setHeader('ETag', etag); // 设置etag if (etag !== ifNoneMatch) { return false }
-
最终方案
-
一般使用lastModified + size
const lastModified = statObj.ctime.toGMTString(); const etag = lastModified + statObj.size; // 加上size,防止1秒内修改了n次,size可以监听到变化 const ifNoneMatch = req.headers['if-none-match']; res.setHeader('ETag', etag) if (etag === ifNoneMatch) { return true // 修改状态码为304,使用缓存 }
-
如果同时设置强缓存和协商缓存,Cache-Control: max-age=5, ETag: xxx,则每次请求后5秒内都使用强缓存,5秒后使用协商缓存,然后重新使用强缓存(相当于每5秒中校验一次文件是否发生改变)
常见状态码
-
301 永久重定向 表示请i去的资源分配了新的url,以后应使用新的url
-
302 临时重定向 请求的资源临时分配了新的url,本次请求暂且使用新的url(302表示临时性重定向,重定向的url还有可能还会改变)
重定向后,会使用响应头中的location地址重新访问 -
303 表示请求的资源路径发生改变,使用GET方法请求新的url(与302的功能一样,但是明确指出使用GET方法请求新url)
-
304 协商缓存,表示服务器端资源未改变,可直接使用客户端未过期的缓存
-
400 表示请求报文中存在语法错误
-
401 未认证(权限)
-
403 服务器拒绝访问
-
404 not found
-
405 请求方法出错
-
500 服务器内部错误
-
501 服务器不支持当前请求所需要的某个功能
-
502 网关错误
-
503 由于临时的服务器维护或者过载,服务器当前无法处理请求
-
504 网关超时