一、location 匹配
直接上例子
location ~ /app/(.*)\.mp3 {
return 200 "$uri";
}
# 应该要加上 ~
# 因为这里没加上 ~,所以 curl 127.0.0.1/app2/a.mp3 会匹配到 location /
location /app2/(.*)\.mp3 {
return 200 "$uri";
}
location / {
return 200 "root";
}
测试
# curl 127.0.0.1/app/a.mp3/app/a.mp3# curl 127.0.0.1/app2/a.mp3root
结论:
- 加上 ~ 表示要进行正则匹配,locaiton 右边表达式中的正则符号才会生效
- 如果不需要正则匹配,则不要加上 ~
二、break 和 last
直接上例子
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
return 403;
}
location ~ /download/a/mp3/(.*)\.mp3 {
return 200 "$uri";
}
2.1 break 测试
# curl http://127.0.0.1/download/a/media/a.mp3
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
== nginx log ==
2022/11/20 21:54:54 [notice] 7233#0: *100 "^(/download/.*)/media/(.*)\..*$" matches "/download/a/media/a.mp3", client: 127.0.0.1, server: localhost, request: "GET /download/a/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
2022/11/20 21:54:54 [notice] 7233#0: *100 rewritten data: "/download/a/mp3/a.mp3", args: "", client: 127.0.0.1, server: localhost, request: "GET /download/a/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
2022/11/20 21:54:54 [error] 7233#0: *100 open() "/usr/local/nginx/html/download/a/mp3/a.mp3" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "GET /download/a/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
结论:rewrite 后的 uri /download/a/mp3/a.mp3 虽然能匹配「 location ~ /download/a/mp3/(.*)\.mp3 」,但 break 的表现是直接打开 /usr/local/nginx/html/download/a/mp3/a.mp3,这里 usr/local/nginx/html/ 是 root 的路径。
2.2 last 测试
直接上例子,只是将 2.1 中的 break 改为 last
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
return 403;
}
location ~ /download/a/mp3/(.*)\.mp3 {
return 200 "$uri";
}
测试 1
# curl 127.0.0.1/download/a/media/a.mp3
/download/a/mp3/a.mp3
== nginx log ==
2022/11/20 23:40:37 [notice] 13584#0: *123 "^(/download/.*)/media/(.*)\..*$" matches "/download/a/media/a.mp3", client: 127.0.0.1, server: localhost, request: "GET /download/a/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
2022/11/20 23:40:37 [notice] 13584#0: *123 rewritten data: "/download/a/mp3/a.mp3", args: "", client: 127.0.0.1, server: localhost, request: "GET /download/a/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
结论:重写后的 uri 会再次进行 locaiton 匹配,该测试中,重写后被 「 location ~ /download/a/mp3/(.*)\.mp3 」匹配了。
测试 2
# curl http://127.0.0.1/download/b/media/a.mp3
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.23.1</center>
</body>
</html>
== nginx log ==
2022/11/20 19:07:13 [notice] 5502#0: *80 "^(/download/.*)/media/(.*)\..*$" matches "/download/b/media/a.mp3", client: 127.0.0.1, server: localhost, request: "GET /download/b/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
2022/11/20 19:07:13 [notice] 5502#0: *80 rewritten data: "/download/b/mp3/a.mp3", args: "", client: 127.0.0.1, server: localhost, request: "GET /download/b/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
2022/11/20 19:07:13 [notice] 5502#0: *80 "^(/download/.*)/media/(.*)\..*$" does not match "/download/b/mp3/a.mp3", client: 127.0.0.1, server: localhost, request: "GET /download/b/media/a.mp3 HTTP/1.1", host: "127.0.0.1"
结论:重写后的 uri 再次被「 location /download/ 」匹配了,只是本次 rewrite 的处理中,uri 跟正则表达式匹配不上,所以 rewrite 后面的 return 403 起效果了。
总结:
- break,直接打开重写后的 uri(会默认加上 root 路径前缀)
- last(继续),重写后的 uri 会再次进行 location 匹配,匹配到的 location 处理中可能也会配置 rewrite 指令,所以如果一个请求经历的 rewrite 处理超过 10 次的话,就会直接返回 500。
三、redirect 和 permanent(重定向)
3.1 rewrite 时加上 http(s)
直接上例子
location = /uniframe/uniframe.js {
rewrite ^/(.*) http://www.baidu.com redirect;
}
测试 1
# curl http://127.0.0.1/uniframe/uniframe.js -i
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.23.1
Date: Sun, 20 Nov 2022 06:30:05 GMT
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: http://www.baidu.com
== nginx log ==
2022/11/20 14:29:05 [notice] 22480#0: *28 "^/(.*)" matches "/uniframe/uniframe.js", client: 127.0.0.1, server: localhost, request: "GET /uniframe/uniframe.js HTTP/1.1", host: "127.0.0.1"
2022/11/20 14:29:05 [notice] 22480#0: *28 rewritten redirect: "http://www.baidu.com", client: 127.0.0.1, server: localhost, request: "GET /uniframe/uniframe.js HTTP/1.1", host: "127.0.0.1"
3.2 rewrite 时不加上 http(s)
重定向时会自动加上 http(s)://127.0.0.1
location = /uniframe/uniframe.js {
rewrite ^/(.*) /uniframe-micro/uniframe.js permanent;
}
location ~ /uniframe-micro/uniframe.js {
return 200 "call $uri";
}
测试 1
# curl http://127.0.0.1/uniframe/uniframe.js -i
HTTP/1.1 301 Moved Permanently
Server: nginx/1.23.1
Date: Sun, 20 Nov 2022 08:06:01 GMT
Content-Type: text/html
Content-Length: 169
Location: http://127.0.0.1/uniframe-micro/uniframe.js
Connection: keep-alive
== nginx log ==
2022/11/20 16:06:01 [notice] 31665#0: *42 "^/(.*)" matches "/uniframe/uniframe.js", client: 127.0.0.1, server: localhost, request: "GET /uniframe/uniframe.js HTTP/1.1", host: "127.0.0.1"
2022/11/20 16:06:01 [notice] 31665#0: *42 rewritten redirect: "/uniframe-micro/uniframe.js", client: 127.0.0.1, server: localhost, request: "GET /uniframe/uniframe.js HTTP/1.1", host: "127.0.0.1"
总结:
- permanent 和 redirect 的区别,只是 301 和 302 的区别,其他地方一致。
- 重定向会触发客户端再次发起请求,用 postman 测试的话,在 nginx 的 access.log 中可以看到客户端先后发起了两次请求。但用 curl 测试时,不会对 301/302 返回的 Location 头部中的重定向链接自动发起请求。