HTTP缓存实践

本文最后更新于:8 个月前

HTTP缓存实践

前言

在实践之前,我们需要搞清楚一些问题:

  • Q:http缓存和浏览器缓存,是一回事吗?

    A:不是一回事,http缓存是在http请求时用到的缓存,从第二次发起相同的http get请求起使用。浏览器缓存指:localStorage、sessionStroage、cookie、IndexDB等等。

  • Q:浏览器刷新机制是怎么样的,刷新时产生了哪些动作? A:(见下文)

  • Q:浏览器输入一个url时,又发生了哪些动作?A:先查找 Disk Cache,查找到就直接用,没找到再向服务器请求。

  • Q:http缓存在本地的形式是怎么样的? A:主要有两种,内存缓存和磁盘缓存

  • Q:内存缓存、硬盘缓存,两者的差异是什么? A:HTTP缓存 - timegogo

  • Q:浏览器的缓存机制是怎么工作的?A:(见下文)

  • Q:什么是前端的http缓存?什么又是后端的http缓存?分别怎么设置? A:前端设置缓存一般是在html的<meta>标签中设置。后端设置http缓存一般实在网页服务器如Nginx中配置

一、用户行为对缓存的影响

1、刷新 / 回车

  • 浏览器强制刷新(Ctrl+F5),对本地缓存文件过期处理,并且跳过强缓存和协商缓存,直接向服务器重新请求
  • 浏览器刷新(F5),对本地缓存文件过期处理,然后带If-Modifed-SinceIf-None-Match发起协商缓存验证新鲜度
  • 浏览器输入URL回车,浏览器查找 Disk Cache,有则使用,没有则发送网络请求

img

2、网络状态码解读

  • 200 OK (来自内存缓存)

    强缓存命中,直接使用内存的缓存,没有向服务器发送请求

  • 200 OK (来自磁盘缓存)

    强缓存命中,没有向服务器发送请求,不过用的是磁盘里的缓存

  • 304 OK

    协商缓存命中,经过与服务器协商,内容没有更改,直接使用本地缓存

三、浏览器缓存机制

1、浏览器缓存工作流程

img

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
    • 查找浏览器缓存的顺序为:先内存缓存 –> 再磁盘缓存
    • 如果强缓存命中,直接用缓存,不再发送请求
    • 如果强缓存过期了,携带上If-None-MatchIf-Modified-Since等字段向服务器发送请求,进行协商缓存环节。
    • 如果协商缓存成功,直接用缓存;否则重新请求资源
  • 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中

2、浏览器会自动管理缓存

仔细观察可以发现,即使我们在服务端没有做任何关于http缓存的设置,浏览器访问我们的网页时,依然会对资源进行缓存。这是因为浏览器自动会管理缓存。

在不定义缓存设置时,不同浏览器有不同的行为。有时,同一浏览器在相同的情形下每次运行的行为都有可能不同。

当然,我们可以主动地进行缓存的设置,以达到我们期望的效果、或者规避一些安全问题。

以下是实践部分

四、配置http缓存

1、html中配置

主要是在<head>标签中嵌入<meta>标签,这种方式只对页面有效,对页面上的资源无效。

  • 禁用强缓存(使用协商缓存)

    1
    2
    3
    4
    5
    6
    方式一
    <meta http-equiv="cache-control" content="no-cache"> #http1.1以上
    <meta http-equiv="pragma" content="no-cache"> #兼容http1.0

    方式二
    <meta http-equiv="Cache-Control" content="max-age=0" />
  • 禁用缓存

    1
    <meta http-equiv="cache-control" content="no-store">
  • 使用强缓存

    1
    <meta http-equiv="Cache-Control" content="max-age=10" />

经过实际测试,发现并没有起到效果。测试条件为:阿里云服务器+Apache

image-20221122193226667

image-20221122193252278 image-20221122193310458

观察上图,可以看到<meta>标签中的Cache-Control属性并没有起作用。

2、Nginx配置http缓存

常用的web服务器有:nginx、apache。这里我们以Nginx服务器为例进行实践。

Nginx其它配置见:Nginx服务器 - timegogo。这里只介绍配置http缓存部分。其实就是在响应头中添加Cache-Control字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# /etc/nginx/nginx.conf
http {
...
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
......

#配置http缓存,用二级路径/test_cache/进行实验
location ~ /test_cache.*\.(gif|jpg|jpeg|png)$ {
root /timegogo/;
add_header Cache-Control max-age=10;
}
location /test_cache{
root /timegogo/;
index index.html;
add_header Cache-Control no-cache;
}

......
}
}

上面的配置表示图片文件设置10秒的有效期,即使用强缓存,html文件使用协商缓存。

请求URL为:https://www.timegogo.top/test_cache/,目录/test_cahe/下放置了一个html和一张jpeg图片

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>测试http缓存</h1>
<img src="./photo.jpeg" alt="photo.jpeg" style="width: 500px;">
</body>
</html>

第一次输入URL请求网页:

image-20221126004932146

10秒内再次刷新:图片使用强缓存;html使用协商缓存

image-20221126005136160

10秒后刷新:图片过期,进入协商缓存环节;html依然使用协商缓存

image-20221126005149120

五、缓存应用策略

  • 频繁变动的资源,用协商缓存

    1
    Cache-Control: no-cache

    使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小。

  • 不常变化的资源,用强缓存,即把缓存有效期设长一点

    1
    Cache-Control: max-age=31536000

    这样浏览器之后请求相同的 URL 会命中强制缓存。

    而为了解决更新的问题,就需要在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效 (其实并未立即失效,只是不再使用了而已)。如果存在没有 hash 值的静态文件,建议不设置强制缓存,仅设置协商缓存

    在线提供的类库 (如 jquery-3.3.1.min.js, lodash.min.js 等) 均采用这个模式。

  • 同一个网页中的资源,使用的缓存策略并不一致,根据实际情况而异。

    比如,有些资源使用强缓存,有些直接禁用强缓存。


HTTP缓存实践
http://timegogo.top/2022/11/19/HTTP/HTTP缓存实践/
作者
丘智聪
发布于
2022年11月19日
更新于
2023年7月16日
许可协议