【Nginx12】Nginx学习:HTTP核心模块(九)浏览器缓存与try_files

Nginx学习:HTTP核心模块(九)浏览器缓存与try_files

浏览器缓存在 Nginx 的 HTTP 核心模块中其实只有两个简单的配置,这一块也是 HTTP 的基础知识。之前我们就一直在强调,学习 Nginx 需要的就是各种网络相关的基础知识,其中更重要的就是 HTTP 和 TCP 相关的内容。另外一个 try_files 配置指令也是 Nginx 中非常常用的一个指令,用于找不到指定的路径文件时,可以去按顺序查找备用的一些文件路径,非常实用。

浏览器缓存

在 HTTP 协议中,有许多和浏览器缓存有关的选项,而在 Nginx 的核心配置中,也有两个与之相关的配置。

if_modified_since

if_modified_since 是由浏览器发送的,让服务端来判断返回 200 还是 304 ,在 Nginx 中,它用于指定响应的修改时间与 if_modified_since 请求头的比较方法。

go 复制代码
if_modified_since off | exact | before;

默认值是 exact ,每个选项分别代表:

  • off 忽略 "If-Modified-Since" 请求头 (0.7.34)

  • exact 精确匹配

  • before 响应的修改时间小于等于 "If-Modified-Since" 请求头指定的时间

etag

etag 是由服务器端生成的,客户端通过发送 If-Match 或者 If-None-Match 这个条件判断请求来验证资源是否修改。Nginx 中,这个配置可以开启或关闭为静态文件自动计算 "ETag" 响应头。

go 复制代码
etag on | off;

它的默认值是 on 。

测试

正常情况下,我们第一次打开某个静态页面,是没有 if_modified_since 的,服务端会返回 ETag 和 Last-Modified 以及 200 状态码。

然后第二次请求的时候,浏览器就会带上 if_modified_since ,服务端会返回 304 表示使用本地缓存就可以了。

这是在默认情况下。现在我们修改 Nginx 的配置,先将 if_modified_since 设置为 off ,然后强刷页面之后再进行普通刷新 ,会发现不管是强刷还是普通刷新,响应头和请求虽然没有什么变化,但服务端都只会返回 200 了。也就是说,服务端不会去比较浏览器发送过来的 if_modified_since 值来判断是否返回 304 。

接下来测试 etag ,这个就麻烦一点,首先,我们要将 if_modified_since 设置为 before ,意思就是访问的静态资源文件的修改时间小于当前浏览器提供的 If-Modified-Since 时,才返回 200 。这样的话,如果我们手动修改文件的时间,将时间修改到当前时间之后很长的一段时间,那么就可以让浏览器在非强刷的状态下一直返回 304 。

go 复制代码
touch -m -d "2023-09-08 12:23:04" /usr/local/nginx/html/aaa.html

默认 etag 为 on 的情况下,你再次修改文件的时间,依然会正常返回一次 200 。这就是 etag 的作用,它是根据文件一些属性进行综合 Hash 从而返回一个值,客户端保存上回的 etag 值后传送到服务端进行比对。而如果现在你将 etag 设置为 off 的话,那么再次请求就不会有 Etag 响应头返回了,这时修改文件的时间,甚至是修改文件的内容(注意修改内容后还要手动修改一下文件的修改时间,否则 if_modified_since 就会生效返回 200 了),后面的请求也将一直会是 304 (非强刷)。

ps.浏览器强刷其实就是浏览器不带任何和 HTTP 缓存有关的请求头进行一次请求访问。

Etag 最主要解决的其实是 if_modified_since 的一些缺点,比如说有些时候可能我们只是周期性地修改一下文件,但文件内容不发生变化(只是文件修改时间变动),这时其实可以不用重新 200 响应的。另外还有 if_modified_since 只支持到秒级,而 Etag 的 Hash 变化是跟随文件变动的,因此它的粒度更细一些。还有一种情况就是某些服务器不能精确的得到文件的最后修改时间,这也会导致 if_modified_since 产生问题,更典型的就是客户端时间和服务器时间不同步,比如有的人的电脑可能时间一直就是错的。

这一块的内容是 HTTP 的基础知识,而且写文字也不太好描述怎么测试,大家可以关注下后期的视频哈,在视频中咱们再好好演示。

try_files

按指定顺序检查文件是否存在,并且使用第一个找到的文件来处理请求,那么处理过程就是在当前上下文环境中进行的。

go 复制代码
try_files file ... uri;
try_files file ... =code;

其实就是我们不确定用户访问的路径或者文件存不存在,这时可以按照 try_files 指定的顺序来展示指定的 URI ,通常它都会和 $uri 变量一起搭配使用,$uri 变量就是当前访问的 location 地址。说白了,就是给请求的链接准备好备胎,能够为用户带来更优良的用户体验。

文件路径是根据 root 指令和 alias 指令,将 file 参数拼接而成。 可以在名字尾部添加斜线以检查目录是否存在,比如"$uri/"。 如果找不到任何文件,将按最后一个参数指定的uri进行内部跳转。 比如:

go 复制代码
location /tf1/ {
 try_files $uri /50x.php;
}

现在试试访问 /tf1 ,会发现显示的是 50x.php 的内容,如果 /tf1 下面有页面的话,那么直接访问就可以查看到指定的页面。这种感觉是不是有点像 error_page ,其实上面的内容就相当于是下面这样的代码。

go 复制代码
location /tf1/ {
 error_page 404 /50x.php;
}

$uri 变量表示的是规范以后的 URI ,也就是拼接请求之后完整的 URI 路径。不过这个变量的值可能会随着请求的处理过程而改变,比如,当进行内部跳转时,或者使用默认页文件时。

这下就看出来了吧,try_files 按顺序,如果第一个 $uri 找到文件了,就直接使用这个文件,如果没找到,就找第二个,依次类推,我们也可以一直向后多写几个 uri ,直到有一个能够找到对应的文件。

go 复制代码
location /tf2/ {
 try_files $uri /tf2/1.html /tf2/2.html;
}

在 tf2 目录下,建立了两个文件,然后访问 /tf2 ,会显示 1.html 的内容,访问 /tf2/2.html ,正常显示 2.html 的内容,按顺序来说 $uri 是第一位的,后面的顺序哪个先找到就按哪个来。因此,除了指定访问 /tf2/2.html 之外,其它链接都会打开 1.html (如果有 404 的 error_page 设置,则直接走 404 的)。那么如果是跳转 uri 呢?比如我们跳转到 php 的 URI 上。

go 复制代码
location /tf3/ {
 try_files $uri /50x.php /404.php;
}

随便访问 /tf3 或者目录中的任意不存在的路径,我这里会弹出下载,查看请求 Content-Type 会变成 application/octet-stream ,下载的文件是 php 的源码。注意,这里是个坑点,不要在静态配置中进行这样的 try_files 。换成带 PHP 相关配置的再试试。

go 复制代码
location /tf4/ {
 try_files $uri /tf4/1.php /1.php =404;
 
 fastcgi_pass unix:/var/sock/php-fpm/www.sock;
 fastcgi_index  index.php;
 fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
 include        fastcgi_params;
}

现在访问 /tf4 会显示到最外面那个我们之前测试的时候打印所有 $_SERVER 内容的 1.php 页面。如果我们创建 tf4 目录,并且添加一个 1.php ,并打印 echo "this is tf4/1.php."; 那么,再次刷新,页面就会展示 this is tf4/1.php. 。这样才能正常的显示 php 。不过我们直接用静态配置去 try_files 动态文件也有别的方法,就是使用命名 location 。

go 复制代码
location /tf5/ {
   try_files $uri @tf5php;
}
location @tf5php {
  root html;
  fastcgi_pass unix:/var/sock/php-fpm/www.sock;
  fastcgi_index  index.php;
  fastcgi_param  SCRIPT_FILENAME  $document_root/tf5php/index.php;
  include        fastcgi_params;
}

访问 /tf5 或者 /tf5/xxx.html ,都会打开 tf5php 目录下的 index.php 文件。注意,这里演示的是从 静态 文件到 php 文件,如果是 /tf5/xxx.php 则会被之前我们配置过的 ~ \.php 的配置拿走,不会走到这边来。

我们再来看看响应码的问题。

go 复制代码
location /tf6/ {
  try_files $uri $uri/ /xxx.html  =401;
}

这一段表示的是如果前面 uri... 部分都没有匹配到,那么就会返回 401 的状态码。大家可以自己试一下访问 /tf6 下的任意文件,最后返回的都是 401 状态。

好了,我们再来看一下 Laravel 文档中给的一个 Nginx 配置,其中有一段内容是大部分 PHP 应用在部署的时候也都会要求写上的。

go 复制代码
location / {
  try_files $uri $uri/ /index.php?$query_string;
 }

在全局的 location 中,访问 uri 页面或者 uri/ 目录,找不到文件的话,会转给 /index.php,并且把请求行的 GET 参数转给 /index.php 文件。通常现代化的框架都是单一入口,index.php 总是可以接收请求的,如果确实还是找不到,也将由 PHP 应用来进行对应的 404 或者 500 处理。

另外,try_files 还可以做一件非常常见的事,就是显示默认图片。

go 复制代码
location /images/ {
    try_files $uri /images/default.gif;
}

正常的图片路径找不到图片了,就使用默认的图片来代替,这也是很多网站的基本需求。

总结

今天的内容不难吧,加起来就是三个配置项,不过我们做了很多的测试。缓存对于现代化的 Web 开发来说非常重要,而 HTTP 缓存则是最前端的面向客户一级的缓存。对于静态资源来说,有着非常重要的作用,可以大大减少服务器的压力。而 try_files 的灵活则为我们带来了更多的特色功能,类似于默认图片这类的配置都能够非常简单方便。

不过估计大家平常可能对这几个指令用得也并不多,毕竟缓存那两个都有默认值,我们保持默认就好了。而 try_files 通常最多的就是用在上文所说的全局路径的处理上,是使用 Laravel 时必备的一个配置。但是,通过今天的学习,相信咱们将来在需要的时候,也能马上想起来这些配置指令的用法,能够更加灵活自如的运用它们。学习,就是这样一步一步的不断积累,一次一次的不停实践。

参考文档:

http://nginx.org/en/docs/http/ngx_http_core_module.html

相关推荐
yunhuibin7 分钟前
ffmpeg面向对象——拉流协议匹配机制探索
学习·ffmpeg
hengzhepa17 分钟前
ElasticSearch备考 -- Search across cluster
学习·elasticsearch·搜索引擎·全文检索·es
C++忠实粉丝23 分钟前
Linux环境基础开发工具使用(2)
linux·运维·服务器
康熙38bdc1 小时前
Linux 环境变量
linux·运维·服务器
鄃鳕1 小时前
HTTP【网络】
网络·网络协议·http
存储服务专家StorageExpert1 小时前
DELL SC compellent存储的四种访问方式
运维·服务器·存储维护·emc存储
蜡笔小新星1 小时前
Python Kivy库学习路线
开发语言·网络·经验分享·python·学习
攸攸太上1 小时前
JMeter学习
java·后端·学习·jmeter·微服务
Ljubim.te2 小时前
Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】
linux·学习·centos
大G哥2 小时前
记一次K8S 环境应用nginx stable-alpine 解析内部域名失败排查思路
运维·nginx·云原生·容器·kubernetes