Nginx在浏览器上的缓存行为

1、Nginx默认配置下的缓存行为

以下演示用的 Nginx 版本都是 1.12.2,默认的demo项目目录如下:

index.html 和 test.html 文件内容基本一样,只是为了测试浏览器会不会对文件名采取不同缓存行为。

文件内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>index.html缓存测试</title>

    <link rel="stylesheet" href="./index.css">
    <link rel="stylesheet" href="./wentest.css">
</head>
<body>
    <h1>index.html缓存测试</h1>

    <img src="./imgtest.png" alt="">
    <img src="./index.jpg" alt="">
    <img src="./test02.jpg" alt="">

    <script src="./index.js"></script>
    <script src="./wentest.js"></script>

</body>
</html>

 

以默认的 Nginx 配置为准,具体如下。(下面的 Nginx 配置跟默认配置基本保持一致,只是修改了访问时指向的资源路径,未做任何缓存配置。)

#user  nobody;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
 
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
 
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
 
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name  localhost;
        location =/ {
            root /usr/local/nginx/html/mytest;
            index index.html;
        }

        location ~* \.(html|gif|jpg|jpeg|css|js|png|ico|eot|ttf|woff|svg)$ {
            root /usr/local/nginx/html/mytest;
        }
    }
}

分别访问 index.html 和 test.html,可以发现,两者的缓存行为是一样的,可以证明,浏览器的缓存行为跟文件名无关。

 

1.1、Chrome浏览器缓存表现

以下用的Chrome浏览器版本都是127.0.6533.100(正式版本) (64 位)

 

1.1.1、首次访问

第一次访问结果如下,可以看到第一次访问状态码都是 200,且都是没有缓存记录的,

通过查看 Nginx 日志可以看到访问记录,如下:

 

html 文件和其他文件的请求头和响应头分别如下:

  • html 文件:

  • JS、CSS 和图片文件:

    

可以看出,首次访问时都不会命中缓存,而且 Chrome 浏览器默认都会往请求头中添加 Cache-Control: no-cache,即告诉服务器浏览器需要通过协商缓存来判定是否使用浏览器缓存。而服务器默认会返回 ETag 和 Last-modified 响应头信息,以此告诉浏览器关于缓存的信息。

 

1.1.2、再次访问

在进行首次访问后,多次刷新浏览器(F5键)或间隔长时间再刷新浏览器,可以看到,此时浏览器对资源进行了缓存,并且浏览器对 html 文件的缓存行为和其他资源的不一样。

查看 Nginx 日志可以看到Nginx 只接收到了 html 的请求,浏览器对于其他资源是直接取的浏览器缓存,并没有往服务器发起请求。如下,状态是 304,文件大小 0

 

html 文件和 其他文件的请求头和响应头分别如下:

  • html 文件:

  • JS、CSS 和图片文件:

     

 

1.1.3、结论

Nginx 默认配置,在 Chrome 浏览器中:

  • 首次访问,永远不会使用缓存(因为浏览器此时还没有缓存该资源),但是浏览器会在请求头中会带上强制缓存标识 Cache-Control: no-cache(这实际上也是告诉服务器使用协商缓存),而 Nginx 服务器也会在资源的响应头加上协商缓存的标识( 包括ETag 和 Last-Modified )。
  • 再次访问时或间隔较长时间再访问,此时全部都会使用缓存,不同的是,html 文件会使用协商缓存,而其他资源都使用强缓存。

所以说,Nginx 默认配置下,在 Chrome 浏览器中,首次访问,资源不会使用缓存;再次访问,html 文件会使用协商缓存,而其他资源都使用强缓存;

 

1.2、Firefox 浏览器缓存表现

Firefox 浏览器(124.0.2 (64 位))缓存行为其实跟 Chrome 浏览器一样。首次访问时不会命中缓存,短时间内再次访问时 html 文件会通过协商缓存判断是否取浏览器缓存,而其他资源也是直接取浏览器缓存。

  • 首次访问

  • 再次访问

 

1.3、更新服务器资源时的缓存表现(模拟生产部署)

我们更新服务器上的 index.html、index.js、index.css、index.jpg 文件,模拟生产上的部署,更新完后不重启 Nginx(实际上重启 Nginx 并不会影响缓存效果),刷新浏览器,第一次请求如下:

  •  index.html 响应信息

  • index.js 响应信息

可以看到,index.html 能正常请求到最新资源,并且last-modified 已经发生了改变;但是 index.js、index.css 等资源并无法请求最新资源,还是命中缓存且 last-modified 没变。

 

再次请求如下:

可以看到又回到初始状态,html 文件命中协商缓存,其他资源使用强制缓存。

 

2、Nginx生产配置下的缓存行为

生存上关于 Nginx 的缓存的配置一般也不会太负载,一般只是会配置下静态资源缓存短暂时间。如下基本还原了真实的 Nginx 生产配置:

#user  nobody;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
 
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
 
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
 
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name  localhost;
        location =/ {
            root /usr/local/nginx/html/mytest;
            index index.html;
        }

        location ~* \.(html|gif|jpg|jpeg|css|js|png|ico|eot|ttf|woff|svg)$ {
            root /usr/local/nginx/html/mytest;
            expires 1m;
        }
    }
}

如上,真实的生产配置往往只会往静态资源添加短暂时间的强制缓存(如上例1分钟)。更新 Nginx 配置,重启 Nginx,访问浏览器可以发现:

  1. 首次访问时,浏览器如果没有缓存则不会命中缓存,资源响应全都是 200 响应码
  2. 一分钟内多次访问时,html 文件仍然是 304 即会使用协商缓存,但其他资源会依照 Nginx 命中强制缓存
  3. 相隔一分钟之后再次访问,html 文件仍然是 304 使用协商缓存,其他资源也变成 304 响应码,即会依照 Nginx 配置命中协商缓存

可以证明,在 Nginx 中配置了静态资源的强制缓存后,除 html 文件外其他资源在配置的时间内是能命中强制缓存的,超过配置时间后会通过协商缓存来获取资源。但是强制缓存对 html 文件是没用的(至少验证了在 Chrome、Firefox 浏览器中是这样的),即不管是否配置了强制缓存,浏览器都会对 html 文件使用协商缓存。浏览器的这一行为往往也符合真实的场景和真实的需要。

 

3、最佳实践

最佳实践配置示例如下:

#user  nobody;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
 
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
 
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
 
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name  localhost;
        location =/ {
            root /usr/local/nginx/html/mytest;
            index index.html;
        }

        location ~* \.(html|gif|jpg|jpeg|css|js|png|ico|eot|ttf|woff|svg)$ {
            root /usr/local/nginx/html/mytest;
            expires 1m;
        } 
    }
}

说明:

  • 最佳配置说明:给所有除 html 外的静态资源配置短时间的强制缓存,如1分钟。(或者也包含 html 文件,因为上面的实践表明,即使给 html 配置了强制缓存,浏览器针对 html 文件使用的永远都是协商缓存)
  • 原因说明:首次访问后,在1分钟内浏览器都会命中强制缓存(html除外),不会往 Nginx 发送请求,这可以提高页面访问速度。在1分钟之后,强制缓存失效,浏览器发出请求,由服务器决定是否使用缓存。所以如果服务器资源有更新的话那么浏览器也能在1分钟之后获取到最新的资源。

实际现在很多前端项目都会需要 build 编译,编译过后 js、css、图片等资源名称会加上时间戳后缀(一般编译后 html 文件名不会加后缀),即名称已改变,而 html 文件一直都是协商缓存,所以一旦重新部署更新了 html 文件,浏览器可以立即获取到最新的 html 文件,而最新的 html 文件里引入的其他资源名称已经发生了改变,所以也可以获取到最新的其他资源文件。这种情况下也可以保证用户能一直获取到最新资源,即使不配置任何缓存配置。

 

posted @ 2021-08-08 19:00  wenxuehai  阅读(523)  评论(0编辑  收藏  举报
//右下角添加目录