Nginx 配置指令的执行顺序(六)

简介: 前面我们在 (五) 中提到,在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”。那么当一个 location 中未使用任何 content 阶段的指令,即没有模块注册“内容处理程序”时,content 阶段会发生什么事情呢?谁又来担负起生成内容和输出响应的重担呢?答案就是那些把当前请求的 URI 映射到文件系统的静态资源服务模块。

前面我们在 (五) 中提到,在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”。那么当一个 location 中未使用任何 content 阶段的指令,即没有模块注册“内容处理程序”时,content 阶段会发生什么事情呢?谁又来担负起生成内容和输出响应的重担呢?答案就是那些把当前请求的 URI 映射到文件系统的静态资源服务模块。当存在“内容处理程序”时,这些静态资源服务模块并不会起作用;反之,请求的处理权就会自动落到这些模块上。

 

    Nginx 一般会在 content 阶段安排三个这样的静态资源服务模块(除非你的 Nginx 在构造时显式禁用了这三个模块中的一个或者多个,又或者启用了这种类型的其他模块)。按照它们在 content 阶段的运行顺序,依次是 ngx_index 模块,ngx_autoindex 模块,以及 ngx_static 模块。下面就来逐一介绍一下这三个模块。

 

    ngx_index 和 ngx_autoindex 模块都只会作用于那些 URI 以 / 结尾的请求,例如请求 GET /cats/,而对于不以 / 结尾的请求则会直接忽略,同时把处理权移交给 content 阶段的下一个模块。而 ngx_static 模块则刚好相反,直接忽略那些 URI 以 / 结尾的请求。

 

    ngx_index 模块主要用于在文件系统目录中自动查找指定的首页文件,类似 index.html 和 index.htm 这样的,例如:

    location / {
        root /var/www/;
        index index.htm index.html;
    }

这样,当用户请求 / 地址时,Nginx 就会自动在 root 配置指令指定的文件系统目录下依次寻找 index.htm 和index.html 这两个文件。如果 index.htm 文件存在,则直接发起“内部跳转”到 /index.htm 这个新的地址;而如果 index.htm 文件不存在,则继续检查 index.html 是否存在。如果存在,同样发起“内部跳转”到/index.html;如果 index.html 文件仍然不存在,则放弃处理权给 content 阶段的下一个模块。

 

    我们前面已经在 Nginx 变量漫谈(二) 中提到, echo_exec 指令和 rewrite 指令可以发起“内部跳转”。这种跳转会自动修改当前请求的 URI,并且重新匹配与之对应的 location 配置块,再重新执行rewriteaccesscontent 等处理阶段。因为是“内部跳转”,所以有别于 HTTP 协议中定义的基于 302 和 301 响应的“外部跳转”,最终用户的浏览器的地址栏也不会发生变化,依然是原来的 URI 位置。而ngx_index 模块一旦找到了 index 指令中列举的文件之后,就会发起这样的“内部跳转”,仿佛用户是直接请求的这个文件所对应的 URI 一样。

 

    为了进一步确认 ngx_index 模块在找到文件时的“内部跳转”行为,我们不妨设计下面这个小例子:

    location / {
        root /var/www/;
        index index.html;
    }
 
    location /index.html {
        set $a 32;
        echo "a = $a";
    }

此时我们在本机的 /var/www/ 目录下创建一个空白的 index.html 文件,并确保该文件的权限设置对于运行 Nginx worker 进程的帐户可读。然后我们来请求一下根位置(/):

    $ curl 'http://localhost:8080/'
    a = 32

这里发生了什么?为什么输出不是 index.html 文件的内容(即空白)?首先对于用户的原始请求 GET /,Nginx 匹配出 location / 来处理它,然后 content 阶段的 ngx_index 模块在 /var/www/ 下找到了index.html,于是立即发起一个到 /index.html 位置的“内部跳转”。

 

    到这里,相信大家都不会有问题。接下来有趣的事情发生了!在重新为 /index.html 这个新位置匹配location 配置块时,location /index.html 的优先级要高于 location /,因为 location 块按照 URI 前缀来匹配时遵循所谓的“最长子串匹配语义”。这样,在进入 location /index.html 配置块之后,又重新开始执行rewrite 、access、以及 content 等阶段。最终输出 a = 32 自然也就在情理之中了。

 

    我们接着研究上面这个例子。如果此时把 /var/www/index.html 文件删除,再访问 / 又会发生什么事情呢?答案是返回 403 Forbidden 出错页。为什么呢?因为 ngx_index 模块找不到 index 指令指定的文件(在这里就是 index.html),接着把处理权转给 content 阶段的后续模块,而后续的模块也都无法处理这个请求,于是 Nginx 只好放弃,输出了错误页,并且在 Nginx 错误日志中留下了类似这一行信息:

    [error] 28789#0: *1 directory index of "/var/www/" is forbidden

所谓 directory index 便是生成“目录索引”的意思,典型的方式就是生成一个网页,上面列举出 /var/www/目录下的所有文件和子目录。而运行在 ngx_index 模块之后的 ngx_autoindex 模块就可以用于自动生成这样的“目录索引”网页。我们来把上例修改一下:

    location / {
        root /var/www/;
        index index.html;
        autoindex on;
    }

此时仍然保持文件系统中的 /var/www/index.html 文件不存在。我们再访问 / 位置时,就会得到一张漂亮的网页:

    $ curl 'http://localhost:8080/'
    <html>
    <head><title>Index of /</title></head>
    <body bgcolor="white">
    <h1>Index of /</h1><hr><pre><a href="../">../</a>
    <a href="cgi-bin/">cgi-bin/</a>  08-Mar-2010 19:36   -
    <a href="error/">error/</a>      08-Mar-2010 19:36   -
    <a href="htdocs/">htdocs/</a>    05-Apr-2010 03:55   -
    <a href="icons/">icons/</a>      08-Mar-2010 19:36   -
    </pre><hr></body>
    </html>

生成的 HTML 源码显示,我本机的 /var/www/ 目录下还有 cgi-bin/error/htdocs/, 以及 icons/ 这几个子目录。在你的系统中尝试上面的例子,输出很可能会不太一样。

 

    值得一提的是,当你的文件系统中存在 /var/www/index.html 时,优先运行的 ngx_index 模块就会发起“内部跳转”,根本轮不到 ngx_autoindex 执行。感兴趣的读者可以自己测试一下。

 

    在 content 阶段默认“垫底”的最后一个模块便是极为常用的 ngx_static 模块。这个模块主要实现服务静态文件的功能。比方说,一个网站的静态资源,包括静态 .html 文件、静态 .css 文件、静态 .js 文件、以及静态图片文件等等,全部可以通过这个模块对外服务。前面介绍的 ngx_index 模块虽然可以在指定的首页文件存在时发起“内部跳转”,但真正把相应的首页文件服务出去(即把该文件的内容作为响应体数据输出,并设置相应的响应头),还是得靠这个 ngx_static 模块来完成。

目录
相关文章
|
18天前
|
移动开发 前端开发 JavaScript
前端vue2、vue3去掉url路由“ # ”号——nginx配置(一)
前端vue2、vue3去掉url路由“ # ”号——nginx配置
52 0
|
18天前
|
JavaScript 前端开发 应用服务中间件
angular引入包、路由权限配置、打包问题与nginx配置问题(简单部署)
angular引入包、路由权限配置、打包问题与nginx配置问题(简单部署)
24 0
|
1月前
|
安全 应用服务中间件 Linux
linux nginx的配置总结
linux nginx的配置总结
19 0
|
18天前
|
前端开发 JavaScript 应用服务中间件
前端vue2、vue3去掉url路由“ # ”号——nginx配置(二)
前端vue2、vue3去掉url路由“ # ”号——nginx配置
48 0
|
2天前
|
应用服务中间件 nginx
nginx配置集群轮训策略
nginx配置集群轮训策略
10 0
|
3天前
|
安全 网络协议 应用服务中间件
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略
一文读懂HTTPS⭐揭秘加密传输背后的原理与Nginx配置攻略
|
11天前
|
应用服务中间件 PHP nginx
php如何实现检测nginx配置的正确性
请确保在执行此操作时,PHP有足够的权限来执行Nginx命令和访问Nginx配置文件。另外,将上述代码嵌入到您的应用程序中时,要注意安全性,以防止潜在的命令注入攻击。
50 3
|
18天前
|
安全 应用服务中间件 网络安全
linux_nginx中添加ssl配置(open ssl)
linux_nginx中添加ssl配置(open ssl)
25 1
|
18天前
|
JSON JavaScript 前端开发
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
33 1
|
21天前
|
安全 应用服务中间件 网络安全
SSL原理、生成SSL密钥对、Nginx配置SSL
现在,你的Nginx虚拟主机应该已经配置了SSL,可以通过HTTPS安全访问。确保在生产环境中使用有效的SSL证书来保护通信的安全性。
32 0