文章目录
  1. 1. Nginx变量漫谈(一)
  2. 2. Nginx变量漫谈(二)
  3. 3. Nginx变量漫谈(三)
  4. 4. Nginx变量漫谈(四)
  5. 5. Nginx变量漫谈(五)
  6. 6. Nginx变量漫谈(六)
  7. 7. Nginx变量漫谈(七)
  8. 8. Nginx变量漫谈(八)
  9. 9. Nginx 配置指令的执行顺序(一)
  10. 10. Nginx 配置指令的执行顺序(二)
  11. 11. Nginx 配置指令的执行顺序(三)
  12. 12. Nginx 配置指令的执行顺序(四)
  13. 13. Nginx 配置指令的执行顺序(五)
  14. 14. Nginx 配置指令的执行顺序(六)
  15. 15. Nginx 配置指令的执行顺序(七)
  16. 16. Nginx 配置指令的执行顺序(八)
  17. 17. Nginx 配置指令的执行顺序(九)
  18. 18. Nginx 配置指令的执行顺序(十)
  19. 19. Nginx 配置指令的执行顺序(十一)
  20. 20. 传送门

Nginx变量漫谈(一)

Nginx变量只能存放一种类型的值,即字符串。 Nginx变量前加$,与PerlPHP类似。 变量的创建与赋值操作是分为两个时间阶段的。虽然变量在整个配置(跨locationserver)可见的,但是每个请求都有他自己的独立副本,互不干扰。我们记住它不是全局共享的「全局变量」。

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 脚本的执行阶段的顺序,供参考:

1
2
3
4
5
6
7
8
9
location /mixed {
set_by_lua $a 'ngx.log(ngx.ERR, "set_by_lua")';
rewrite_by_lua 'ngx.log(ngx.ERR, "rewrite_by_lua")';
access_by_lua 'ngx.log(ngx.ERR, "access_by_lua")';
content_by_lua 'ngx.log(ngx.ERR, "content_by_lua")';
header_filter_by_lua 'ngx.log(ngx.ERR, "header_filter_by_lua")';
body_filter_by_lua 'ngx.log(ngx.ERR, "body_filter_by_lua")';
log_by_lua 'ngx.log(ngx.ERR, "log_by_lua")';
}

我们在使用一条陌生的配置指令时,如何判断它究竟是运行在哪一个运行阶段呢?可以通过文档(或者 C 源码),文档中会标注该指令的运行阶段。如 echo 指令:

1
phase: content

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 阶段指令时,只会有其中一个模块成功去处理。比如:

1
2
3
4
5
location /test {
echo "before...";
content_by_lua 'ngx.say("hello")';
echo "after...";
}

这里只会输出 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 个阶段:

  1. post-read
    • ngx_realip 模块
  2. server-rewrite
  3. find-config
  4. rewrite
    • ngx_rewrite 模块
  5. post-rewrite
  6. preaccess
    • ngx_realip 模块
  7. access
    • ngx_auth_request 模块
    • ngx_lua 模块
    • access_by_lua 模块
  8. post-access
  9. try-files
  10. content
  11. 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

传送门

文章目录
  1. 1. Nginx变量漫谈(一)
  2. 2. Nginx变量漫谈(二)
  3. 3. Nginx变量漫谈(三)
  4. 4. Nginx变量漫谈(四)
  5. 5. Nginx变量漫谈(五)
  6. 6. Nginx变量漫谈(六)
  7. 7. Nginx变量漫谈(七)
  8. 8. Nginx变量漫谈(八)
  9. 9. Nginx 配置指令的执行顺序(一)
  10. 10. Nginx 配置指令的执行顺序(二)
  11. 11. Nginx 配置指令的执行顺序(三)
  12. 12. Nginx 配置指令的执行顺序(四)
  13. 13. Nginx 配置指令的执行顺序(五)
  14. 14. Nginx 配置指令的执行顺序(六)
  15. 15. Nginx 配置指令的执行顺序(七)
  16. 16. Nginx 配置指令的执行顺序(八)
  17. 17. Nginx 配置指令的执行顺序(九)
  18. 18. Nginx 配置指令的执行顺序(十)
  19. 19. Nginx 配置指令的执行顺序(十一)
  20. 20. 传送门