前言
日常工作和生活中都免不了遇到和HTTP缓存相关的问题。比如发现本该更新的文件因为缓存而没有更新,通常的做法给请求资源的文件路径加个时间戳,简单粗暴又有效。为了能让你的服务器更加快速的访问你想要的东西,思考下是否还有更好的解决方案?针对不同的场景、不同类型的资源,有没有更高效的缓存设计方案?希望你读完这篇文章之后,能对HTTP缓存有更深刻全面的理解,掌握它们,对我们解决日常一些复杂问题会有帮助。
缓存用来做什么?
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。对于网站来说,缓存是达到高性能的重要组成部分。缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。
缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。本文将主要介绍浏览器与代理缓存,除此之外还有网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上的缓存方式,为站点和 web 应用提供更好的稳定性、性能和扩展性。
虽然 HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。然而常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。
1:强制缓存
强制缓存是通过利用客户端本地缓存直接返回资源,避免每次都向服务器发起请求。在强制缓存的有效期内,客户端将优先从本地缓存加载资源,而无需重新请求服务器。通常,通过在响应头中设置 `Cache-Control: max-age=seconds` 或 `Expires: datetime`,来控制资源的缓存有效期,确保客户端在有效期内直接使用缓存数据,而不需再次访问服务器。
使用nginx配置为例子
Cache-Control
Cache-Control 头告诉浏览器资源的最大缓存时间为多少秒。在 Nginx 中,可以通过add_header Cache-Control来配置
location ~* \.(html|css|js|png|jpg)$ {
// 设置资源的最大缓存时间为3600秒(1小时)
add_header Cache-Control "max-age=3600, public";
}
location ~* \.(html|css|js|png|jpg)$ {
// 如果不想让代理或浏览器缓存,加 no-cache 参数
Cache-Control: no-cache;
}这样浏览器 F5 刷新时,nginx 静态资源缓存 设置返回的状态码就是 http 200,而不是 http 304
Expires
Expires 告诉浏览器在多长时间内缓存资源。在 Nginx 中,可以通过 expires 指令来配置 Expires 。
location ~* \.(html|css|js|png|jpg)$ {
expires: 3d; // 缓存3天
}expires 3d; // 表示缓存 3 天
expires 3h; // 表示缓存 3 小时
expires 3y; // 表示缓存 1 年
expires max; // 表示缓存 10 年
expires -1; // 表示永远过期。2:协商缓存
当资源的强制缓存过期或客户端首次请求资源时,客户端会向服务器发送请求。服务器会检查资源是否有更新。如果资源未发生变化,服务器会返回 `304 Not Modified` 状态码,并通过响应头中的 `Last-Modified` 或 `ETag` 与客户端缓存的值进行比对,告知客户端继续使用本地缓存。这种机制被称为协商缓存,因为它要求客户端与服务器就缓存资源的新鲜度进行协商确认。
Last-Modified
Last-Modified 是指资源的最后修改时间,在 Nginx 中可以通过 add_header Last-Modified 来配置。
location ~* \.(html|css|js)$ {
add_header Last-Modified $date_gmt;
}ETag
ETag 是一个由服务器生成的唯一标识符,用于标志资源变化。在 Nginx 中,可以通过 etag 指令来配置 ETag
location ~* \.(html|css|js)$ {
etag on;
}3:私有缓存
私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。
private 指令
Cache-Control: private,如果响应具有 Authorization 标头,则不能将其存储在私有缓存(或共享缓存,除非 Cache-Control 指定的是 public)中。
4:共享缓存
共享缓存大至又分为代理缓存和托管缓存。
代理缓存
Cache-Control: no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate托管缓存
Cache-Control: no-store5:启发式缓存
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html>
…总结
HTTP的缓存方式还有很多的,博主这边就简单的介绍了些常用的缓存方式。缓存的方式 不一样使用的场景也是不一样的,每个人的使用需求都是不同的,尽量根据自己的需求去选择相应的缓存方式。自有适合自己的才是最好的!前面博主也分享了HTTPS原理及理论基础,有需求的也可以去看下。
参考资料:
https://blog.csdn.net/csdn_yudong/article/details/141497056
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Cache-Control
https://jecyu.github.io/Web-Performance-Optimization/cache/browser-cache.html