Nginx 之 Location

nginx Location 官网文档
语法 语法介绍

location [=|~|~*|^~|@] uri { ... } location @name { ... }

一个 location 关键字,后面跟着可选的修饰符(就是[]中间的正则),后面是要匹配的字符,花括号中是要执行的操作。
  • =:表示精确匹配
  • ~:表示区分大小写正则匹配
  • ~*:表示不区分大小写正则匹配
  • ^~:表示 URI 以某个常规字符串开头
  • !~:表示区分大小写正则不匹配
  • !~*:表示不区分大小写正则不匹配
  • /:通用匹配,任何请求都会匹配到
匹配顺序
多个 location 配置的情况下,匹配顺序如下:
1、首先精确匹配=
location = /abcd { […] }

  • website.com/abcd:匹配
  • website.com/ABCD:可能会匹配,也可以不匹配,取决于操作系统的文件系统是否大小写敏感。Mac 默认是大小写不敏感,Windows 不区分大小,Linux 区分大小写。
  • website.com/abcd?param1¶m2:匹配,忽略 querystring
  • website.com/abcd/:不匹配,带有结尾的/
  • website.com/abcde:不匹配
所以经常请求/的话,可以使用=来定义 location。
2、其次前缀匹配^~
如果该 location 是最佳的匹配,那么对于匹配这个 location 的字符串,立刻停止后续的正则搜索。注意,这不是一个正则表达式匹配,它的目的是优先于正则表达式的匹配。
3、接着是按文件中顺序的正则匹配(regular expression),如~~*
location ~ ^/abcd$ { […] }

^/abcd$这个正则表达式表示字符串必须以/开始,以$结束,中间必须是abcd
  • website.com/abcd:匹配(完全匹配)
  • website.com/ABCD:不匹配,大小写敏感
  • website.com/abcd?param1¶m2:匹配
  • website.com/abcd/:不匹配,不能匹配正则表达式
  • website.com/abcde:不匹配,不能匹配正则表达式
4、最后是匹配不带任何修饰的前缀匹配(prefix string)
检查使用前缀字符串的 locations,在使用前缀字符串的 locations 中选择最长匹配的来匹配。
server { location /doc { [ configuration A ] } location /docu { [ configuration B ] } }

/document能匹配上面 2 个,但前缀字符串顺序不重要,按照匹配长度来确定,所以最终匹配到B
小结,匹配顺序就是先=^~,然后是正则,最后是前缀字符串匹配。如果上述规则不好理解,可以看下面的伪代码
function match(uri): rv = NULLif uri in exact_match: return exact_match[uri]if uri in prefix_match: if prefix_match[uri] is '^~': return prefix_match[uri] else: rv = prefix_match[uri] // 注意这里没有 return,且这里是最长匹配if uri in regex_match: return regex_match[uri] // 按文件中顺序,找到即返回 return rv

@name 的用法
@用来定义一个命名 location。主要用于内部重定向,不能用来处理正常的请求。其用法如下:
location / { try_files $uri $uri/ @custom } location @custom { # ...do something }

上例中,当尝试访问 url 找不到对应的文件就重定向到我们自定义的命名 location(此处为 custom)。
注意,命名 location 中不能再嵌套其它的命名 location。
常用配置规则
1、精确匹配
# 将所有请求直接转发给服务器的9090端口 location = / { proxy_pass http://127.0.0.1:9090/; }

2、处理静态文件
# 目录匹配 location ^~ /static/ { root /webroot/static/; }# 后缀匹配 location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { root /webroot/res/; }

3、转发动态请求到后端应用服务器
# 将/account/开始的请求转发给Account服务器 location /account/ { proxy_pass http://127.0.0.1:8080/ }# 将/order/开始的请求转发给Order服务器 location /order/ { proxy_pass http://127.0.0.1:9090/ }

URL 尾部的/需不需要
URL 尾部是否需要带/,也是我入门 nginx 经常搞错的。
1、location 中的字符有无/,都没有影响
也就是说/user//user是一样的,除非 location 中带了$对 url 有要求,可参考前面例子。
2、URL 结构是https://domain.com/的形式,尾部有没有/都不会造成重定向。
因为浏览器在发起请求的时候,默认加上了/,不过很多浏览器在地址栏里也不会显示/
Nginx 之 Location
文章图片

3、如果 URL 的结构是https://domain.com/some-dir/,尾部如果缺少/将导致重定向。
因为根据约定,URL 尾部的/表示目录,没有/表示文件。所以访问/some-dir/时,服务器会自动去该目录下找对应的默认文件。如果访问/some-dir 的话,服务器会先去找 some-dir 文件,找不到的话会将 some-dir 当成目录,重定向到/some-dir/,去该目录下找默认文件。
root 与 alias nginx 指定文件路径有两种方式 root 和 alias,主要区别在于 nginx 如何解释 location 后面的 uri,这会使两者分别以不同的方式将请求映射到服务器文件上。它们的使用方法和作用域:
[root]
语法:root path
默认值:root html
配置段:http、server、location、if
处理结果:root 路径+ location 路径
[alias]
语法:alias path
配置段:location
处理结果:使用 alias 路径替换 location 路径
如果一个请求的 URI 是/t/a.html 时,它们表现如下:
# 返回/www/root/html/t/a.html的文件 location ^~ /t/ { root /www/root/html/; }# 返回/www/root/html/new_t/a.html的文件 # 把location后面配置的路径丢弃掉,把当前匹配到的目录指向到指定的目录。 location ^~ /t/ { alias /www/root/html/new_t/; }

可以看出 alias 是一个目录别名的定义,root 则是最上层目录的定义。另外 alias 后面必须要用/结束,否则会找不到文件的,而 root 则可有可无。
那如果 server 和 location 中都出现 root,是怎样的优先级呢??
http { server { listen 80; server_name www.abc.com; root /home/www/website/; location / { root /home/www/ts/; index index.html; } } }

简单的来说是就近原则,如果 location 中能匹配到,就是用 location 中的 root 配置,忽略 server 中的 root,当 location 中匹配不到的时候,则使用 server 中的 root 配置。
【Nginx 之 Location】参考资料:
  • Nginx 正则配置
  • 彻底弄懂 Nginx location 匹配
  • 一份简单够用的 Nginx Location 配置讲解
  • 一文弄懂 Nginx 的 location 匹配
  • nginx 中 location 和 root,你确定真的明白他们关系?
  • 大小写敏感知多少

    推荐阅读