添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
耍酷的甘蔗  ·  Error cannot load ...·  1 周前    · 
勤奋的鸭蛋  ·  RUN Instruction Using ...·  5 天前    · 
着急的打火机  ·  Docker installation - ...·  4 月前    · 
唠叨的松树  ·  Font (Java Platform ...·  4 月前    · 
淡定的猴子  ·  REGEXEXTRACT - ...·  5 月前    · 

Levon's Blog

微信: L6241425

0%

nginx的location和rewrite使用规则

0. 前言

uri是url中除去协议和域名及参数后, 剩下的部分.

比如请求的url为: http://www.liuvv.com/test/index.php?page=1 , 则uri 为 /test/index.php

1. location指令

1.1 location匹配uri的规则

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

1.2 location匹配uri的优先级

  1. 首先先检查使用前缀字符定义的location,选择最长匹配的项并记录下来。

  2. 如果找到了精确匹配的location,也就是使用了 = 修饰符的location,结束查找,使用它的配置。

  3. 如果 ^~ 修饰符先匹配到最长的前缀字符串, 则不检查正则。

  4. 然后按顺序查找使用正则定义的location,如果匹配则停止查找,使用它定义的配置。

  5. 如果没有匹配的正则location,则使用前面记录的最长匹配前缀字符location。

基于以上的匹配过程,我们可以得到以下启示:

  1. 使用正则定义的location在配置文件中出现的顺序很重要。因为找到第一个匹配的正则后,查找就停止了,后面定义的正则就是再匹配也没有机会了。
  2. 使用精确匹配可以提高查找的速度。例如经常请求 / 的话,可以使用 = 来定义location。
  3. 优先级 = > ^~ > 正则

1.3 location 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
location = / {
return 502 "规则A\n";
}
location = /login {
return 502 "规则B\n";
}
location ^~ /static/ {
return 502 "规则C\n";
}
location ^~ /static/files {
return 502 "规则D\n";
}
location ~ \.(gif|jpg|png|js|css)$ {
return 502 "规则E\n";
}
location ~* \.PNG$ {
return 502 "规则F\n";
}
location /img {
return 502 "规则G\n";
}
location / {
return 502 "规则H\n";
}

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
levonfly@hk:~$ curl test.liuvv.com # 因为是=
规则A
levonfly@hk:~$ curl test.liuvv.com/ # 因为是=
规则A
levonfly@hk:~$ curl test.liuvv.com/login # 因为是=
规则B
levonfly@hk:~$ curl test.liuvv.com/login/ # 多了/, 参考下面3.5
规则H
levonfly@hk:~$ curl test.liuvv.com/abc
规则H

levonfly@hk:~$ curl test.liuvv.com/static/a.html
规则C
levonfly@hk:~$ curl test.liuvv.com/static/files/a.html # 更加精准
规则D

levonfly@hk:~$ curl test.liuvv.com/a.png # 正则精准
规则E
levonfly@hk:~$ curl test.liuvv.com/a.PNG # 正则精准
规则F
levonfly@hk:~$ curl test.liuvv.com/static/a.png # ^~ 优先级更高
规则C

levonfly@hk:~$ curl test.liuvv.com/img/a.gif #正则匹配优先
规则E
levonfly@hk:~$ curl test.liuvv.com/img/a.tiff
规则G
levonfly@hk:~$ curl test.liuvv.com/abc/123/haha #什么都匹配不到, 就到H
规则H

1.4 location @name的用法

@用来定义一个命名location。主要用于内部重定向,不能用来处理正常的请求。其用法如下:

1
2
3
4
5
6
location / {
try_files $uri $uri/ @custom
}
location @custom {
# ...do something
}

上例中,当尝试访问url找不到对应的文件就重定向到我们自定义的命名location(此处为custom)。

值得注意的是,命名location中不能再嵌套其它的命名location。

1.5 root和alias的区别

nginx指定文件路径有两种方式root和alias.

1
2
3
4
[root]
语法:root path
默认值:root html
配置段:http、server、location、if

例如:

1
2
3
location ^~ /t/ { 
root /www/root/html/;
}

如果一个请求的URI是/t/a.html时,web服务器将会返回服务器上的/www/root/html/t/a.html的文件。

1
2
3
[alias]
语法:alias path
配置段:location

例如:

1
2
3
location ^~ /t/ { # 特殊的规则是, alias必须以"/" 结束
alias /www/root/html/new_t/;
}

如果一个请求的URI是/t/a.html时,web服务器将会返回服务器上的/www/root/html/new_t/a.html的文件。注意这里是new_t,因为alias会把location后面配置的路径丢弃掉,把当前匹配到的目录指向到指定的目录。

1.6 nginx显示目录结构

nginx默认是不允许列出整个目录的。如需此功能, 在server或location 段里添加上autoindex on;

1
2
3
4
5
6
7
autoindex_exact_size off;
默认为on,显示出文件的确切大小,单位是bytes。
改为off后,显示出文件的大概大小,单位是kB或者MB或者GB

autoindex_localtime on;
默认为off,显示的文件时间为GMT时间。
改为on后,显示的文件时间为文件的服务器时间

可以下面的例子:

1
2
3
4
5
location ^~ "/upload-preview" {
alias /tmp/cistern/;
autoindex on;
autoindex_localtime on;
}

1.7 URL尾部的 / 需不需要

2. rewirte规则

2.1 return指令

return指令写在server和location里面

1
2
3
return code [text];
return code URL;
return URL;

我们来看下面这个例子

1
return 301 $scheme://www.baidu.com$request_uri; 

return 指令告诉 nginx 停止处理请求, 直接返回301代码和指定重写过的URL到客户端. $scheme是指协议(http),$request_uri指包含参数的完整URI

对于 3xx 系列响应码, url参数就是重写的url

1
return (301 | 302 | 303 | 307) url;

对于其他响应吗, 可以出现一个字符串

1
return (1xx | 2xx | 4xx | 5xx)["text"]

例如:

1
return 401 "Access denied because token is expired or invalid";

2.2 rewrite指令

rewrite指令写在server和location里面, 规则会改变部分或整个用户的URL.

1
rewrite regex URL [flag]
  1. regex 正则表达式

  2. flag

  3. rewrite只能返回301或302, 如果有其他,需要后面加上return, 例如:

1
2
3
rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last;
return 403;

2.3 try_files指令

try_files指令写在server和location里面.

1
try_files file ... uri 或 try_files file ... = code

try_files 指令的参数是一个或多个文件或目录的列表, 以及后面的uri参数. nginx会按照顺序检查文件或目录是否存在, 并用找到的第一个文件提供服务. 如果都不存在, 内部重定向到最后的这个uri

例如:

1
2
3
4
5
6
7
location /images/ {
try_files $uri $uri/ /images/default.gif;
}

location = /images/default.gif {
expires 30s;
}

try_files常用的变量:

我们看个例子:

1
2
try_files /app/cache/ $uri @fallback; 
index index.php index.html;

它将检测$document_root/app/cache/index.php,$document_root/app/cache/index.html 和 $document_root$uri是否存在,如果不存在着内部重定向到@fallback(@表示配置文件中预定义标记点) 。

你也可以使用一个文件或者状态码(=404)作为最后一个参数,如果是最后一个参数是文件,那么这个文件必须存在。

我们来看一个错误:

1
2
3
4
location ~.*\.(gif|jpg|jpeg|png)$ {
root /web/wwwroot;
try_files /static/$uri $uri;
}

原意图是访问 http://example.com/test.jpg 时先去检查 /web/wwwroot/static/test.jpg 是否存在,不存在就取 /web/wwwroot/test.jpg

但由于最后一个参数是一个内部重定向,所以并不会检查 /web/wwwroot/test.jpg 是否存在,只要第一个路径不存在就会重新向然后再进入这个location造成死循环。结果出现500 Internal Server Error

1
2
3
4
location ~.*\.(gif|jpg|jpeg|png)$ {
root /web/wwwroot;
try_files /static/$uri $uri 404;
}

这样才会先检查 /web/wwwroot/static/test.jpg 是否存在,不存在就取 /web/wwwroot/test.jpg 再不存在则返回404 not found

2.4 if指令

if不是系统级的指令, 是和rewrite配合的. if 必须写在server和location里面.

例如下面的列子:

1
2
3
4
5
6
7
8
9
10
11
12
if ($http_user_agent ~ Chrome) {
rewrite ^([^/]*)$ /chrome$1 break;
}

if ($request_method = POST){
return 405;
}

if (-f $request_filename) {
expires max;
break;
}

3. proxy_pass模块

proxy_pass指令是将请求反向代理到URL参数指定的服务器上,URL可以是主机名或者IP地址+端口号的形式,例如:

1
2
proxy_pass http://proxy_server;
proxy_pass http://192.168.9.2:8000;

3.1 基本配置

3.2 proxy_set_header

1
2
3
4
5
6
7
语法:    proxy_set_header field value;
默认值:
proxy_set_header Host $proxy_host; # 注意这个是proxy_host
proxy_set_header Connection close;


上下文: http, server, location

允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。默认情况下,只有两个请求头会被重新定义:

1
2
proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

proxy_set_header也可以自定义参数,如:proxy_set_header test paroxy_test;

3.3 获取真实ip

经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip, 通过$remote_addr变量拿到的将是反向代理服务器的ip地址. 如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

1
proxy_set_header            X-real-ip $remote_addr;

其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:request.getAttribute(“X-real-ip”)

3.4 常见配置解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
server {
server_name liuwei.fhyx.com;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;

location / {
proxy_pass http://127.0.0.1:8000;
}

location ~ "/(box|c|bub)/" {
proxy_pass http://127.0.0.1:8081;
}

location ~ /(a|o2)/ {
proxy_pass http://127.0.0.1:3010;
}

location ~ "/api/(v\d{1,2})/" {
proxy_pass http://127.0.0.1:5010;
}

}

4. websocket反向代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#必须添加的
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

upstream websocket {
ip_hash;
#转发到服务器上相应的ws端口
server localhost:3344;
server localhost:8011;
}
server {
listen 80;
server_name a.liuvv.com;
location / {

#转发到http://websocket
proxy_pass http://websocket;
proxy_read_timeout 300s;
proxy_send_timeout 300s;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

#升级http1.1到 websocket协议
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

5. 参考资料

可以加首页作者微信,咨询相关问题!
levon 微信支付

微信支付

levon 支付宝

支付宝