「agentzh的Nginx教程」笔记
更新日期:
- 1. Nginx变量漫谈(一)
- 2. Nginx变量漫谈(二)
- 3. Nginx变量漫谈(三)
- 4. Nginx变量漫谈(四)
- 5. Nginx变量漫谈(五)
- 6. Nginx变量漫谈(六)
- 7. Nginx变量漫谈(七)
- 8. Nginx变量漫谈(八)
- 9. Nginx 配置指令的执行顺序(一)
- 10. Nginx 配置指令的执行顺序(二)
- 11. Nginx 配置指令的执行顺序(三)
- 12. Nginx 配置指令的执行顺序(四)
- 13. Nginx 配置指令的执行顺序(五)
- 14. Nginx 配置指令的执行顺序(六)
- 15. Nginx 配置指令的执行顺序(七)
- 16. Nginx 配置指令的执行顺序(八)
- 17. Nginx 配置指令的执行顺序(九)
- 18. Nginx 配置指令的执行顺序(十)
- 19. Nginx 配置指令的执行顺序(十一)
- 20. 传送门
Nginx变量漫谈(一)
Nginx变量只能存放一种类型的值,即字符串。
Nginx变量前加$
,与Perl
,PHP
类似。
变量的创建与赋值操作是分为两个时间阶段的。虽然变量在整个配置(跨location
,server
)可见的,但是每个请求都有他自己的独立副本,互不干扰。我们记住它不是全局共享的「全局变量」。
Nginx变量漫谈(二)
三种方式的跳转:
- | 内部跳转 | 302跳转 | 301跳转 |
---|---|---|---|
标准模块ngx_rewrite |
rewrite ^ /bar; |
rewrite ^ /bar redirect; |
rewrite ^ /bar permanent; |
第三方模块echo_exec |
echo_exec /bar; |
- | - |
Openresty/Lua | return ngx.exec("/bar") |
return ngx.redirect("/bar") |
return ngx.redirect("/bar", 301) |
Nginx变量值容器的生命期与当前正在处理的请求相关,与location
无关。
内建变量 $uri
表示当前请求的URI(经过解码的,不含请求参数)
内建变量 $request_uri
表示当前请求最原始的URI(未经解码,且含请求参数)
内建变量 $arg_xxx
表示当前请求名为xxx
的URI参数的值(未解码)。
许多内建变量是只读,但我们要绝对避免对他们进行赋值,可能会Nginx进程导致崩溃。
Nginx变量漫谈(三)
很多新手都会对
$arg_XXX
的实现方式产生误解,以为 Nginx 会事先解析好当前请求的所有 URL 参数,并且把相关的$arg_XXX
变量的值都事先设置好。然而事实并非如此,Nginx 根本不会事先就解析好 URL 参数串,而是在用户读取某个$arg_XXX
变量时,调用其“取处理程序”,即时去扫描 URL 参数串。类似地,内建变量$cookie_XXX
也是通过它的“取处理程序”,即时去扫描 Cookie 请求头中的相关定义的。
Nginx变量漫谈(四)
变量值的缓存机制,以及「惰性求值」(lazy evaluation)。
Nginx变量漫谈(五)
子请求:
与 HTTP 相似,但无网络通信。其目的在于把一个请求分解为多个较小颗粒的「内部请求」,或并发或串行地完成。
主请求与子请求都有着不同的变量值容器副本,但也有一些 Nginx 模块(如ngx_auth_request
)中子请求与其父请求共享同一套的变量值容器。
Nginx变量漫谈(六)
Nginx 内建变量用在“子请求”的上下文中时,其行为也会变得有些微妙。
标准模块 ngx_http_core 提供的内建变量 $request_method 只作用于主请求,意思是子请求中的它也会是主请求对应的值,不管子请求的实际情况是什么样子。如果有必要,我们可以用第三方模块 ngx_echo 中的内建变量 $echo_request_method
来替代。
父子请求间的变量共享,实在不是一个好主意。
Nginx变量漫谈(七)
变量只有一种类型:字符串,但是它有可能是压根不存在有意义的值 nil
。
Nginx变量漫谈(八)
虽然我们说变量只有字符串这一种类型,但是一些第三方模块(如:ngx_array_var
)提供存放数组类型的值。
Nginx 配置指令的执行顺序(一)
Nginx 的请求处理阶段有很多,它们的执行先后顺序需要注意下。比如常见的 3 个的先后顺序依次为: rewrite 阶段、access 阶段以及 content 阶段。这有点类似 JavaScript 中变量与函数的定义是先于语句的执行,不能以代码的书写顺序来判断。
此外,下面是 Openresty 中 Lua 脚本的执行阶段的顺序,供参考:
我们在使用一条陌生的配置指令时,如何判断它究竟是运行在哪一个运行阶段呢?可以通过文档(或者 C 源码),文档中会标注该指令的运行阶段。如 echo 指令:
Nginx 配置指令的执行顺序(二)
标准 ngx_rewrite 模块
Nginx 配置指令的执行顺序(三)
more_set_input_headers 与 rewrite_by_lua 指令都是运行在 rewrite 阶段的末尾。但是它们两者的先后顺序则不一定。
在 rewrite 阶段之后,是一个名为 access 的请求处理阶段。比如:标准模块 ngx_access 中的 allow 与 deny 指令可用于控制哪些 IP 地址可以访问,哪些禁止。
看到这儿,才回想起之前的配置经历,因为没有弄明白 access 阶段在 rewrite 阶段之后,想当然地以为 allow 和 deny 指令可以过滤掉白名单外的 IP 的某些请求,而这些请求又用到 rewrite 指令。结果老是不对,原来是这样。
作者agentzh
提醒到,
为了避免阅读配置时的混乱,我们应该总是让指令的书写顺序和它们的实际执行顺序保持一致。
Nginx 配置指令的执行顺序(四)
标准模块 ngx_access 比 Openresty 中的 access_by_lua 模块性能大约快一个数量级,但它们的绝对时间差极小。
access_by_lua 运行于 access 阶段的末尾,其他如 rewrite_by_lua 类似,运行于 rewrite 阶段末尾,等等。
Nginx 配置指令的执行顺序(五)
一个 location 只能有一个「内容处理程序」,所以,当同时使用多个模块的 content 阶段指令时,只会有其中一个模块成功去处理。比如:
这里只会输出 hello 。原因是 echo 指令来自 ngx_echo 模块, content_by_lua 指令来自于 ngx_lua 模块,二者都是作用于 content 阶段,最终只会有一个指令成功处理。
如要达成,我们可以变通地使用 echo_before_body 与 echo_after_body。
Nginx 配置指令的执行顺序(六)
当没有 content 阶段没有对应的内容处理程序时,Nginx 会安排三个静态资源服务模块来处理请求,按先后顺序,它们分别: ngx_index 模块,ngx_autoindex 模块,ngx_static 模块。前二者仅处理 URI 以 /
结尾的请求,相对地,第三个模块会忽略那些URI 以 /
结尾的请求。
index 指令会优先于 autoindex 完成「内部跳转」,当有 index 指令时, autoindex 无效。
index 执行内部跳转后,比如 /index.html
,最后还是由 static 模块来完成内容的提供。
Nginx 配置指令的执行顺序(七)
ngx_static 模块总是处于开启状态,在 content 阶段,优先于它的其他模块都「弃权」转由它来托管处理时,才去根据 root 的配置和请求文件去找寻对应的路径,如果找不到,则返回 404 。
Nginx 配置指令的执行顺序(八)
Nginx 处理请求的 11 个阶段:
- post-read
- ngx_realip 模块
- server-rewrite
- find-config
- rewrite
- ngx_rewrite 模块
- post-rewrite
- preaccess
- ngx_realip 模块
- access
- ngx_auth_request 模块
- ngx_lua 模块
- access_by_lua 模块
- post-access
- try-files
- content
- log
Nginx 配置指令的执行顺序(九)
rewrite 指令在执行时并不会立即进行跳转,原因是可能会有多次 rewrite ,如果马上跳转的话,下面的 rewrite 指令就永远不可能执行到。除非是我们在 server-rewrite 阶段(即在 server 配置块中使用 rewrite 指令)执行的,它会直接完成跳转,因为此时是在 find-config 阶段之前。
Nginx 配置指令的执行顺序(十)
尽量在 server 配置块中配置 ngx_realip 中的指令(如:set_real_ip_from, real_ip_header),避免出现在 preaccess 阶段中的修改不能被其他 rewrite 处理程序所读取,因为 rewrite 阶段先于 preaccess 阶段。
核心模块中的 satisfy 指令如果配置了 all 方式的话,需要 access 阶段的所有模块都通过验证才行。 在 any 方式下,则只要有一个模块通过验证,就认为请求整体通过验证;只有所有模块的处理程序都拒绝访问时,整个请求才会被拒。
Nginx 配置指令的执行顺序(十一)
try_files 指令配置 N 个参数时,前 N-1 个参数用于检查文件或文件夹,只有最后一个参数才会被检测用于 location 内部跳转,当然也可以是返回指定状态码的错误页,比如 404 ,用法:try_files /foo /bar/ =404
。