如何在CentOS8上使用Nginx的头模块实现浏览器缓存
作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
网站加载速度越快,访问者留下的可能性就越大。 当网站充满了由后台加载的脚本运行的图像和交互式内容时,打开网站并不是一件容易的事。 它包括从服务器一个一个地请求许多不同的文件。 尽量减少这些请求的数量是加快网站速度的一种方法。
提高网站性能的一种方法是 浏览器缓存 。 浏览器缓存告诉浏览器它可以重用下载文件的本地版本,而不是一次又一次地向服务器请求它们。 为此,您必须引入新的 HTTP 响应标头,告诉浏览器如何操作。
Nginx 的 header 模块可以帮助你完成浏览器缓存。 您可以使用此模块向响应中添加任意标头,但其主要作用是正确设置缓存标头。 在本教程中,我们将使用 Nginx 的 header 模块来实现浏览器缓存。
先决条件
要遵循本教程,您将需要:
- 使用 this Initial Server Setup tutorial 设置的一台 CentOS 8 服务器,包括 sudo 非 root 用户。
- 按照 如何在 CentOS 8 上安装 Nginx 教程 在您的服务器上安装 Nginx。
第 1 步 - 创建测试文件
在这一步中,我们将在默认的 Nginx 目录中创建几个测试文件。 稍后我们将使用这些文件来检查 Nginx 的默认行为,然后测试浏览器缓存是否正常工作。
为了推断网络上提供了什么样的文件,Nginx 不会分析文件内容; 那将非常缓慢。 相反,它会查找文件扩展名以确定文件的 MIME 类型,这表明了它的用途。
由于这种行为,我们的测试文件的内容是不相关的。 通过适当地命名文件,我们可以诱使 Nginx 认为,例如,一个完全空的文件是图像,另一个是样式表。
使用 truncate
在默认 Nginx 目录中创建一个名为 test.html
的文件。 这个扩展表示它是一个 HTML 页面:
sudo truncate -s 1k /usr/share/nginx/html/test.html
让我们以相同的方式再创建几个测试文件:一个 jpg
图像文件、一个 css
样式表和一个 js
JavaScript 文件:
sudo truncate -s 1k /usr/share/nginx/html/test.jpg sudo truncate -s 1k /usr/share/nginx/html/test.css sudo truncate -s 1k /usr/share/nginx/html/test.js
下一步是检查 Nginx 在使用我们刚刚创建的文件进行全新安装时发送缓存控制标头的行为。
第 2 步 — 检查默认行为
默认情况下,所有文件都将具有相同的默认缓存行为。 为了探索这一点,我们将使用我们在步骤 1 中创建的 HTML 文件,但您可以使用任何示例文件运行这些测试。
因此,让我们检查 test.html
是否提供了有关浏览器应缓存响应多长时间的任何信息。 以下命令从我们的本地 Nginx 服务器请求一个文件并显示响应标头:
curl -I http://localhost/test.html
您应该会看到几个 HTTP 响应标头:
Output: Nginx response headersHTTP/1.1 200 OK Server: nginx/1.14.1 Date: Thu, 04 Feb 2021 18:23:09 GMT Content-Type: text/html Content-Length: 1024 Last-Modified: Thu, 04 Feb 2021 18:22:39 GMT Connection: keep-alive ETag: "601c3b6f-400" Accept-Ranges: bytes
在倒数第二行中,您将找到 ETag
标头,其中包含所请求文件的此特定版本的唯一标识符。 如果重复执行前面的 curl
命令,你会发现完全相同的 ETag
值。
当使用网络浏览器时,ETag
值被存储并在浏览器想要再次请求相同文件时以 If-None-Match
请求标头发送回服务器 - 例如,刷新页面时.
我们可以使用以下命令在命令行上模拟这一点。 确保更改此命令中的 ETag
值以匹配之前输出中的 ETag
值:
curl -I -H 'If-None-Match: "601c3b6f-400"' http://localhost/test.html
现在的响应将有所不同:
Output: Nginx response headersHTTP/1.1 304 Not Modified Server: nginx/1.14.1 Date: Thu, 04 Feb 2021 18:24:05 GMT Last-Modified: Thu, 04 Feb 2021 18:22:39 GMT Connection: keep-alive ETag: "601c3b6f-400"
这一次,Nginx 将响应 304 Not Modified。 它不会再次通过网络发送文件; 相反,它会告诉浏览器它可以重用它已经在本地下载的文件。
这很有用,因为它减少了网络流量,但还不足以实现良好的缓存性能。 ETag
的问题是浏览器总是向服务器发送一个请求,询问它是否可以重用它的缓存文件。 即使服务器以 304 响应而不是再次发送文件,仍然需要时间来发出请求并接收响应。
在下一步中,我们将使用 headers 模块来附加缓存控制信息。 这将使浏览器在本地缓存一些文件,而无需明确询问服务器是否可以这样做。
第 3 步 — 配置 Cache-Control 和 Expires 标头
除了ETag
文件验证头之外,还有两个缓存控制响应头:Cache-Control
和Expires
。 Cache-Control
是较新的版本,具有比 Expires
更多的选项,如果您想更好地控制缓存行为,通常更有用。
如果设置了这些标头,它们可以告诉浏览器所请求的文件可以在本地保存一段时间(包括永久)而无需再次请求。 如果未设置标头,浏览器将始终从服务器请求文件,期望 200 OK 或 304 Not Modified 响应。
我们可以使用 header 模块来设置这些 HTTP 标头。 头模块是一个核心的 Nginx 模块,这意味着它不需要单独安装即可使用。
要添加头模块,请在 vi
中打开默认的服务器块 Nginx 配置文件(这里是 vi 的简短介绍)或您喜欢的文本编辑器:
sudo vi /etc/nginx/nginx.conf
找到 server
配置块:
/etc/nginx/nginx.conf
. . . server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; . . .
在此处添加以下两个新部分:一个在 server
块之前,用于定义缓存不同文件类型的时间,另一个在其中,用于适当地设置缓存头:
修改/etc/nginx/nginx.conf
. . . # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css max; application/javascript max; ~image/ max; ~font/ max; } server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; expires $expires; . . .
server
块之前的部分是一个新的 map
块,它定义了文件类型和这种文件应该被缓存多长时间之间的映射。
我们在这张地图中使用了几种不同的设置:
- 默认值设置为
off
,不会添加任何缓存控制头。 对于内容来说,这是一个安全的赌注,我们对缓存的工作方式没有特别的要求。 - 对于
text/html
,我们将值设置为epoch
。 这是一个明确导致不缓存的特殊值,这会迫使浏览器始终询问网站本身是否是最新的。 - 对于样式表和 JavaScript 文件的
text/css
和application/javascript
,我们将值设置为max
。 这意味着浏览器将尽可能长时间地缓存这些文件,从而大大减少请求的数量,因为这些文件通常有很多。 - 最后两个设置用于
~image/
和~font/
,它们是正则表达式,将匹配在其 MIME 中包含image/
或font/
的所有文件类型键入 名称(如image/jpg
、image/png
或font/woff2
)。 与样式表一样,网站上的图片和网络字体都可以安全缓存以加快页面加载时间,因此我们也将其设置为max
。
注意:这些只是网站上最常见的MIME类型的几个例子。 您可以在 Common MIME types 站点上了解更广泛的此类类型列表,并将其他可能对您的情况有用的地图添加到地图中。
在 server 块内部,expires
指令(headers 模块的一部分)设置缓存控制头。 它使用地图中设置的 $expires
变量的值。 这样,生成的标题将根据文件类型而有所不同。
保存并关闭文件以退出。
要启用新配置,请重启 Nginx:
sudo systemctl restart nginx
接下来,让我们确保我们的新配置有效。
第 4 步 — 测试浏览器缓存
对测试 HTML 文件执行与之前相同的请求:
curl -I http://localhost/test.html
这一次的反应会有所不同。 您将看到两个额外的 HTTP 响应标头:
Nginx 响应头
HTTP/1.1 200 OK Server: nginx/1.14.1 Date: Thu, 04 Feb 2021 18:28:19 GMT Content-Type: text/html Content-Length: 1024 Last-Modified: Thu, 04 Feb 2021 18:22:39 GMT Connection: keep-alive ETag: "601c3b6f-400" Expires: Thu, 01 Jan 1970 00:00:01 GMT Cache-Control: no-cache Accept-Ranges: bytes
Expires
标头显示过去的日期,Cache-Control
设置为 no-cache
,它告诉浏览器始终询问服务器是否有更新版本的文件(像以前一样使用 ETag
标头)。
您会发现测试图像文件的响应有所不同。
curl -I http://localhost/test.jpg
注意新的输出:
Nginx 响应头
HTTP/1.1 200 OK Server: nginx/1.14.1 Date: Thu, 04 Feb 2021 18:29:05 GMT Content-Type: image/jpeg Content-Length: 1024 Last-Modified: Thu, 04 Feb 2021 18:22:42 GMT Connection: keep-alive ETag: "601c3b72-400" Expires: Thu, 31 Dec 2037 23:55:55 GMT Cache-Control: max-age=315360000 Accept-Ranges: bytes
在这种情况下,Expires
显示了遥远的将来的日期,而 Cache-Control
包含了 max-age
信息,它告诉浏览器它可以以秒为单位缓存文件多长时间。 这告诉浏览器尽可能长时间地缓存下载的图像,因此该图像的任何后续出现都将使用本地缓存,根本不会向服务器发送请求。
test.js
和 test.css
的结果应该相似,因为 JavaScript 和样式表文件也都设置了缓存头。
这意味着缓存控制标头已正确配置,您的网站将受益于性能提升和由于浏览器缓存而减少的服务器请求。 您应该根据您网站的内容自定义缓存设置,但本文中的默认设置是一个合理的起点。
结论
headers 模块可用于向响应添加任意标头,但正确设置缓存控制标头是其最有用的应用之一。 它提高了网站用户的性能,尤其是在延迟较高的网络上,如移动运营商网络。 它还可以在将速度测试纳入其结果的搜索引擎上产生更好的结果。 设置浏览器缓存标头是 Google 的 PageSpeed 和类似性能测试工具的重要建议。
您可以在 Nginx 的官方 headers 模块文档 中找到有关 headers 模块 的更多详细信息。