Nginx的配置是一大特色。可以类比css文件中样式的定义,子元素会继承父元素的样式定义并可以选择是否覆盖,nginx配置中同样存在类似的继承关系。(我这样子想但不一定准确)
翻译自UNDERSTANDING THE NGINX CONFIGURATION INHERITANCE MODEL
为理解nginx配置的继承模型,你需要知道nginx配置有好几个块,一个块也被称为一个上下文(context),例如在server上下文中定义的指令存放在server{}块中,http上下文中定义的指令存放在http{}块中。
在nginx中存在6种可能的上下文,顺序从高到低依次是:
- Global
- Http
- Server
- If
- Location
- Nested Location
- if in location
- limit_except
默认的继承模型方向是低层继承高层,而不是横向或逆向。一个常见的场景是,重写请求从一个location内部跳转到另一个location,那么在第一个location块中定义的指令就会被忽略,而只有第二个location块中定义的指令在location context中有效。
按继承行为分,nginx配置指令可分为四种:
- Normal directive:每个context中只有一个值,ie:root、index
- Array directive:每个context可有多个值,ie:access_log,fastcgi_param
- Action directive:不只是配置,ie:rewrite、fastcgi_pass
- try_files
Normal directive是目前最一般的一种,遵循默认的继承模型,看个例子(本文例子与原文有些差别):
server{
root /home/gao/nginx/public_html;
location /app {
root /home/gao/nginx/share; #覆盖掉server中root的配置
#结果存放在路径/home/gao/nginx/share中,
#完整的URI添加到root之后
#比如请求127.0.0.1/app/hello.html,则会返
# 回/home/gao/nginx/share/app/hello.html文件
}
location /app2 {
#继承server中root的配置
#如果请求127.0.0.1/app2/hello.html,
# 则会返回/home/gao/nginx/public_html/app2/hello.html文件
}
}
Array directive很像Normal directive,也遵循默认的继承模型。可能令人迷惑的是这些指令假定你把值添加到列表中,而不是简单赋值,如果你在同一个context中定义多个相同的指令,那么这些指令值会连接在一起,而如果你在不同级的context中定义多个相同的指令,那么低层context中的定义会覆盖掉高层次中的定义。例子:
server{
root /home/gao/nginx/public_html;
access_log /home/gao/nginx/logs/access1.log;
location /app {
root /home/gao/nginx/share;
access_log /home/gao/nginx/logs/access2.log;
access_log /home/gao/nginx/logs/access3.log;
}
}
#在例子中若访问/app开头的URL,则访问日志记录在access2.log和access3.log中,而不会存到
#access1.log中,其他的URL访问日志记录在access1.log中
Action directives是个有趣的地方,它们只限于一个context中,不会进行继承。如果在多级context中都进行指定,那么在每个context中都会执行。rewrite就是一个这样的指令,允许在server context和location context中指定,可能在每个context中都会执行。
server{
rewrite ^/booking(.*) /app$1 permanent;#总是执行
location /app {
rewrite ^ /index.html;#与server context rewrites互不干扰
}
}
但也没这么简单,在location context中有三种可能的context,nested location,if,limit_except。active 指令的具体行为实际上完全依赖于模块是怎样定义的。对normal directives和array directives会在允许的context中恰当地继承,而对active directives情况就有点不同。通常它们不会通过继承传递到嵌套的location context中,而是完全依赖于module的实现,而且对不同的指令,行为也可能不同。ngix文档这时也没什么用处,你只能去尝试,看nginx如何反应。下面是一个例子:
server{
location /share {
rewrite ^ /index.html;#如果内部嵌套的location匹配就不会执行
location ~ \.html$ {
rewrite ^ /50x.html; #外部的rewrite不会执行
}
}
}
#在这个例子中只要开头为/share的URL以.html结尾就显示/50x.html,否则显示/index.html
try_files指令与其他active directive类似,区别是如果放在server context中nginx会创建一个伪location以承接所有没有匹配的请求,即这个伪location为最不精准最泛的一个匹配,相当于定义了location /,那么所有的请求都会被匹配(最差也能匹配location /),而如果请求与一个location匹配,try_files就不会执行,所以尽可能不要把try_files放在server context中。
server {
try_files $uri /index.php; # This never executes.
location / {
# Whatever here, or empty.
}
location ~ \.php$ {
# If this location executes then try_files still does not execute.
# Even if location / did not exist.
}
}