前面章节分别介绍了 nginx 配置文件中 event、http 和 server 配置块,本章节将介绍另一个配置块 location。location 配置块用来配置匹配的不同请求 URL 的处理方式,示例用法:
http { #... server { listen 8080; #... location / { root html; index index.html index.htm; } location /example1 { // 匹配请求 URL 为 /example1 的请求 // 在这里为该请求定义配置信息 } location /example2 { proxy_pass http://localhost:8080/demo/mng/; proxy_cookie_path /demo /; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_redirect ~^http://localhost:8080/demo/mng/(.*) https://www.demo.com/mng/$1; proxy_connect_timeout 4s; proxy_read_timeout 60s; proxy_send_timeout 8s; } } #... }
注意:location 配置块只能在 server 配置块中配置,下面将逐一介绍 location 指令以及 location 配置块下面的指令。
location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 请求,进而对请求做不同的处理和响应,其中较难理解的是多个 location 的匹配顺序。
匹配 URI 类型,有四种参数可选,例如:
location [ = | ~ | ~* | ^~ ] /URI { # ... }
参数说明:
空:location 后没有参数直接跟着标准 URI,表示前缀匹配,代表跟请求中的 URI 从头开始匹配
=:用于标准 URI 前,要求请求字符串与其精准匹配,成功则立即处理,nginx 停止搜索其他匹配
^~:用于标准URI前,并要求一旦匹配到就会立即处理,不再去匹配其他的那些个正则 URI,一般用来匹配目录
~:用于正则 URI 前,表示 URI 包含正则表达式,区分大小写
~*:用于正则 URI 前,表示 URI 包含正则表达式,不区分大小写
@用来定义一个命名location。主要用于内部重定向,不能用来处理正常的请求。语法如下:
location @/name/ { # ... }
参数说明:
@:@ 定义一个命名的 location,@ 定义的 location 名字一般用在内部定向,例如:error_page、try_files 命令中。
用法如下:
location / { try_files $uri $uri/ @custom } location @custom { # ...do something }
上例中,当尝试访问 url 找不到对应的文件就重定向到我们自定义的命名 location(此处为 custom)。
注意:命名 location 中不能再嵌套其它的命名 location。
nginx 用两层指令来匹配请求 URI,如下:
第一层:使用 server 指令,通过域名、ip 和端口来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。
第二层:location 的匹配并不完全按照其在配置文件中出现的顺序来匹配,请求 URI 会按如下规则进行匹配:
(1)先精准匹配 = ,精准匹配成功则会立即停止其他类型匹配;
(2)没有精准匹配成功时,进行前缀匹配。先查找带有 ^~ 的前缀匹配,带有 ^~ 的前缀匹配成功则立即停止其他类型匹配。再进行普通前缀匹配(不带参数 ^~ )成功则会暂存,继续查找正则匹配;
(3)= 和 ^~ 均未匹配成功前提下,查找正则匹配 ~ 和 ~* 。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;所有正则匹配均未成功时,返回步骤(2)中暂存的普通前缀匹配(不带参数 ^~ )结果;
以上规则优先级从高到低依次为:
location = # 精准匹配,优先级最高 location ^~ # 带参前缀匹配 location ~ # 正则匹配(区分大小写) location ~* # 正则匹配(不区分大小写) location /a # 普通前缀匹配,优先级低于带参数前缀匹配。 location / # 任何没有匹配成功的,都会匹配这里处理,优先级最低
假如我们有下面的一段配置文件:
location = / { # 配置A } location / { # 配置B } location /user/ { # 配置C } location ^~ /images/ { # 配置D } location ~* .(gif|jpg|jpeg|png)$ { # 配置E }
匹配实例:
(1)请求 / 精准匹配 A,不再往下查找。
(2)请求 /index.html 匹配 B。首先查找匹配的前缀字符,找到最长匹配是配置 B,接着又按照顺序查找匹配的正则。结果没有找到,因此使用先前标记的最长匹配,即配置 B。
(3)请求 /user/index.html 匹配 C。首先找到最长匹配 C,由于后面没有匹配的正则,所以使用最长匹配C。
(4)请求 /user/1.jpg 匹配 E。首先进行前缀字符的查找,找到最长匹配项 C,继续进行正则查找,找到匹配项 E,因此使用 E。
(5)请求 /images/1.jpg 匹配 D。首先进行前缀字符的查找,找到最长匹配 D。但是,特殊的是它使用了 ^~ 修饰符,不再进行接下来的正则的匹配查找,因此使用 D。这里,如果没有前面的修饰符,其实最终的匹配是 E。大家可以想一想为什么。
(6)请求 /documents/about.html 匹配 B。因为 B 表示任何以 / 开头的 URL 都匹配。在上面的配置中,只有B能满足,所以匹配 B。
该指令用来设置代理服务器的映射地址,映射地址可以使用 http 或 https 协议,而且地址可以使用域名、IP,以及可选的端口。例如:
proxy_pass http://localhost:8080/demo/mng/;
或者在单词 “unix” 之后指定并用冒号括起来的 UNIX 域套接字路径:
proxy_pass http://unix:/tmp/backend.socket:/uri/;
该指令的作用是用来改变 cookie 的路径,语法:
proxy_cookie_path path replacement;
参数说明:
path:就是你要替换的路径
replacement:就是要替换的值
用法示例:
location /example2 { proxy_pass http://localhost:8080/demo/mng/; proxy_cookie_path /demo /; }
该指令允许重新定义或添加字段到传递给代理服务器的请求头。该值可以包含文本、变量及其组合。当且仅当当前级别上没有定义 proxy_set_header 指令时,这些指令才从先前的配置级别继承。默认情况下,只重新定义了两个字段:
proxy_set_header Host $proxy_host; proxy_set_header Connection close;
如果启用缓存,来自之前请求的头字段 “If-Modified-Since”, “If-Unmodified-Since”, “If-None-Match”, “If-Match”, “Range”, 和 “If-Range” 将不会被代理服务器传递。
一个不会变化的“Host”头请求字段可通过如下方式被传递:
proxy_set_header Host $http_host;
然后,当字段不在请求头中就无法传递了,在这种情况下,可通过设置Host变量,将需传递值赋给Host变量。如下:
proxy_set_header Host $host;
此外,服务器名称和端口一起通过代理服务器传递
proxy_set_header Host $host:$proxy_port;
nginx 的 proxy_redirect 功能比较强大,其作用是对发送给客户端的 URL 进行修改。如果需要修改从被代理服务器传来的应答头中的“Location”和“Refresh”字段,可以用这个指令进行设置。假如被代理服务器返回 Location 字段为:
http://localhost:8000/two/some/uri/
下面指令:
proxy_redirect http://localhost:8000/two/ http://frontend/one/;
将 Location 字段重写为 http://frontend/one/some/uri/。
在代替的字段中可以不写服务器名:
proxy_redirect http://localhost:8000/two/ /;
这样就使用服务器的基本名称和端口,即使它来自非 80 端口。
定义与代理服务器建立连接的超时时间,注意:这个超时时间通常不能超过 75 秒。
定义从代理服务器读取响应的超时时间。超时仅在两次连续读取操作之间设置,而不是针对整个响应的传输。如果代理服务器在此时间内未传输任何内容,则连接将关闭。
设置将请求传输到代理服务器的超时时间。超时仅设置在两次连续的写操作之间,而不是针对整个请求的传输。如果代理服务器在此时间内没有收到任何信息,则连接将关闭。