作者选择了COVID-19 救济基金来接受捐赠,作为Write for DOnations计划的一部分。
介绍
网站加载速度越快,访问者停留的可能性就越大。当网站充满图像和由后台加载的脚本运行的交互式内容时,打开网站并不是一项简单的任务。它由一个接一个地从服务器请求许多不同的文件组成。最大限度地减少这些请求的数量是加快网站速度的一种方法。
提高网站性能的一种方法是浏览器缓存。浏览器缓存告诉浏览器它可以重用下载文件的本地版本,而不是一次又一次地向服务器请求它们。为此,您必须引入新的 HTTP 响应标头,告诉浏览器如何操作。
Nginx 的 header 模块可以帮助你完成浏览器缓存。您可以使用此模块向响应添加任意标头,但其主要作用是正确设置缓存标头。在本教程中,我们将使用 Nginx 的头模块来实现浏览器缓存。
先决条件
要学习本教程,您需要:
-
使用此初始服务器设置教程设置的一台 CentOS 8 服务器,包括一个 sudo 非 root 用户。
-
按照如何在 CentOS 8 上安装 Nginx 教程在您的服务器上安装 Nginx。
步骤 1 — 创建测试文件
在这一步中,我们将在默认的 Nginx 目录中创建几个测试文件。我们稍后将使用这些文件来检查 Nginx 的默认行为,然后测试浏览器缓存是否正常工作。
为了推断网络上提供的文件类型,Nginx 不会分析文件内容;那将是非常缓慢的。相反,它查找文件扩展名以确定文件的MIME 类型,这表示其用途。
由于这种行为,我们的测试文件的内容是无关紧要的。通过适当命名文件,我们可以让 Nginx 认为,例如,一个完全空的文件是一个图像,另一个是样式表。
创建一个test.html
在默认 Nginx 目录中命名的文件,使用truncate
. 此扩展名表示它是一个 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
值。
使用 Web 浏览器时,当浏览器想要再次请求相同的文件时(例如,刷新页面时),该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 步 – 配置缓存控制和过期标头
除了ETag
文件验证标头之外,还有两个缓存控制响应标头:Cache-Control
和Expires
. Cache-Control
是较新的版本,有更多的选项Expires
,如果您想更好地控制缓存行为,通常更有用。
如果设置了这些标头,它们可以告诉浏览器所请求的文件可以在本地保留一段时间(包括永远)而无需再次请求。如果未设置标头,浏览器将始终从服务器请求文件,期待200 OK或304 Not Modified响应。
我们可以使用 header 模块来设置这些 HTTP 标头。header 模块是 Nginx 的核心模块,这意味着它不需要单独安装即可使用。
要添加标头模块,请在vi
(这里是对 的简短介绍vi
)或您喜欢的文本编辑器中打开默认的服务器块 Nginx 配置文件:
- sudo vi /etc/nginx/nginx.conf
找到server
配置块:
. . .
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
. . .
在此处添加以下两个新部分:一个在server
块之前,用于定义缓存不同文件类型的时间,另一个在其中,用于适当设置缓存头:
. . .
# 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
。这是一个特殊的值,它明确导致没有缓存,这会强制浏览器始终询问网站本身是否是最新的。 -
对于
text/css
和application/javascript
,它们是样式表和 JavaScript 文件,我们将值设置为max
。这意味着浏览器将尽可能长时间地缓存这些文件,考虑到这些文件通常很多,从而大大减少了请求的数量。 -
最后两个设置是 for
~image/
和~font/
,它们是正则表达式,将匹配包含image/
或包含font/
在其MIME 类型名称中的所有文件类型(如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 响应标头:
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
注意新的输出:
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 模块的更多详细信息。