分享

Nginx的location配置规则梳理

 WindySky 2018-02-07

Nginx几乎是当下绝大多数公司在用的web应用服务,熟悉Nginx的配置,对于我们日常的运维工作是至关重要的,下面就Nginx的location配置进行梳理:

1)location匹配的是nginx的哪个变量?

1
$request_uri

2)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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
格式:location [ 空格 | = | ~ | ~* | !~ | !~* | @ ] /uri/ {}
解释:
=   表示精确匹配,如果找到,立即停止搜索并立即处理此请求。
~   表示执行一个正则匹配,区分大小写匹配
~*  表示执行一个正则匹配,不区分大小写匹配
!~  区分大小写不匹配
!~* 不区分大小写不匹配
^~  即表示只匹配普通字符(空格)。使用前缀匹配,^表示“非”,即不查询正则表达式。如果匹配成功,则不再匹配其他location。
@   指定一个命名的location,一般只用于内部重定向请求。例如 error_page, try_files
/   表示通用匹配,任何请求都会匹配到
------------------------------------------------------------------------
对应示例说明:
1)=
server {
  server_name wangshibo.com;
  location = /abcd {
  […]
  }
}
匹配情况:
    http://wangshibo.com/abcd        # 正好完全匹配
    http://wangshibo.com/ABCD        # 如果运行 Nginx server 的系统本身对大小写不敏感,比如 Windows ,那么也匹配
    http://wangshibo.com/abcd?param1?m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1?m2
    http://wangshibo.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),Nginx 不认为这种情况是完全匹配
    http://wangshibo.com/abcde    # 不匹配,因为不是完全匹配
2)(None)
可以不写 location modifier ,Nginx 仍然能去匹配 pattern 。这种情况下,匹配那些以指定的 patern 开头的 URI,注意这里的 URI 只能是普通字符串,不能使用正则表达式。
server {
  server_name website.com;
  location /abcd {
  […]
  }
}
匹配情况:
    http://wangshibo.com/abcd        # 正好完全匹配
    http://wangshibo.com/ABCD        # 如果运行 Nginx server 的系统本身对大小写不敏感,比如 Windows ,那么也匹配
    http://wangshibo.com/abcd?param1?m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1?m2
    http://wangshibo.com/abcd/    # 末尾存在反斜杠(trailing slash)也属于匹配范围内
    http://wangshibo.com/abcde    # 仍然匹配,因为 URI 是以 pattern 开头的
3)~
这个 location modifier 对大小写敏感,且 pattern 须是正则表达式
server {
  server_name wangshibo.com;
  location ~ ^/abcd$ {
  […]
  }
}
匹配情况:
    http://wangshibo.com/abcd        # 完全匹配
    http://wangshibo.com/ABCD        # 不匹配,~ 对大小写是敏感的
    http://wangshibo.com/abcd?param1?m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1?m2
    http://wangshibo.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),并不匹配正则表达式 ^/abcd$
    http://wangshibo.com/abcde    # 不匹配正则表达式 ^/abcd$
注意:对于一些对大小写不敏感的系统,比如 Windows ,~ 和 ~* 都是不起作用的,这主要是操作系统的原因。
4)~*
与 ~ 类似,但这个 location modifier 不区分大小写,pattern 须是正则表达式
server {
  server_name website.com;
  location ~* ^/abcd$ {
  […]
  }
}
匹配情况:
    http://wangshibo.com/abcd        # 完全匹配
    http://wangshibo.com/ABCD        # 匹配,这就是它不区分大小写的特性
    http://wangshibo.com/abcd?param1?m2    # 忽略查询串参数(query string arguments),这里就是 /abcd 后面的 ?param1?m2
    http://wangshibo.com/abcd/    # 不匹配,因为末尾存在反斜杠(trailing slash),并不匹配正则表达式 ^/abcd$
    http://wangshibo.com/abcde    # 不匹配正则表达式 ^/abcd$
5)^~
匹配情况类似 2. (None) 的情况,以指定匹配模式开头的 URI 被匹配,不同的是,一旦匹配成功,那么 Nginx 就停止去寻找其他的 Location 块进行匹配了(与 Location 匹配顺序有关)
6. @
用于定义一个 Location块,且该块不能被外部Client 所访问,只能被Nginx内部配置指令所访问,比如try_files 或 error_page
    location @resize {
            rewrite ^/(.*)/cache/(.*)?(.*)$ /resize.php?dir=$1&path=$2$3;
            rewrite ^/(.*)/orgi/cert/(.*)?(.*)$ /pass/resize?dir=$1&type=cert&path=$2$3&is_orgi=true;
            rewrite ^/(.*)/orgi/card/(.*)?(.*)$ /pass/resize?dir=$1&type=card&path=$2$3&is_orgi=true;
            rewrite ^/(.*)/orgi/(.*)/(.*)?(.*)$ /pass/resize?dir=$1&type=$2&path=$3$4&is_orgi=true;
            include fastcgi_params;
        }

如下示例:

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
#通用匹配
location / {
      root /var/www/web/;
      autoindex on;
      autoindex_exact_size off;
      autoindex_localtime on;
      access_log /var/www/log/nginx/access.log;
      error_log /var/www/log/nginx/error.log;
}
#正则匹配
#proxy the php scripts to php-fpm
location ~ \.php(.*)$  {
        root /var/www/web/;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_read_timeout 300;
        }
#精确匹配
location = /hello.php {
        root /var/www/web/;
        rewrite ^(.*)$ http://www.wangshibo.com  redirect;
}
产生的效果如下:
访问根目录/,匹配到location /
访问除hello.php之外的其它php程序,匹配到location ~ \.php$,并且用php5-fpm去运行
访问hello.php,匹配到location = /hello.php,访问被重定向到http://www.wangshibo.com

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
精确匹配 > 字符串匹配( 长 > 短 [ 注: ^~ 匹配则停止匹配 ]) > 正则匹配( 上 > 下 )
  
在nginx的location和配置中location的顺序没有太大关系。正location表达式的类型有关。相同类型的表达式,字符串长的会优先匹配。
  
优先级排列:
1)等号类型(=)的精确匹配优先级最高,精确匹配只能命中一个。一旦匹配成功,则不再查找其他匹配项。
2)^~类型表达式,即字符串匹配,使用匹配最长的最为匹配结果。一旦匹配成功,则不再查找其他匹配项。
3)正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
4)常规字符串匹配类型。按前缀匹配。
  
特别注意:
字符串匹配优先搜索,但是只是记录下最长的匹配 (如果 ^~ 是最长的匹配,则会直接命中,停止搜索正则),然后继续搜索正则匹配,如果有正则匹配,则命中正则匹配,如果没有正则匹配,则命中最长的字符串匹配.
  
实例说明:
1)先来测试下区分大小写和不区分大小写的优先级.如下:
  
   location ~ /5b.txt {
          return 501
   }
  
   location ~* /5b.txt {
          return 504
   
  
测试结果为:
http://192.168.1.80/5b.txt ------------501
http://192.168.1.80/5B.txt ------------504
  
将顺序反下,将~*放前面
   location ~* /5b.txt {
          return 501
   }
  
   location ~ /5b.txt {
          return 504
   
  
测试结果为:
http://192.168.1.80/5b.txt ------------501
http://192.168.1.80/5B.txt ------------501
  
结论: 去分和不区分大小写的正则匹配优先级相同,以先后顺序来决定匹配哪一个.
  
2)再来比较=与~的优先级
  
   location = /5b.txt {
          return 502
   }
  
   location ~ /5b.txt {
          return 504
   
  
测试结果为:
http://192.168.1.80/5b.txt -------------502
  
结论:=的优先级比~高
  
3)再来比较下 ^~ 与 ~的优先级
  
   location ~ /5b.txt {
          return 502
   }
  
   location ^~ /5b.txt {
          return 504
   
  
测试结果为:
http://192.168.1.80/5b.txt  --------------504
  
结论:^~的优先级比~高
  
  
4)再测试 ^~ 与 = 的优先级
  
   location ^~ /5b.txt {
          return 502
   }
  
   location = /5b.txt {
          return 504
   
  
测试结果:
http://192.168.1.80/5b.txt  --------------504
  
结论:=的优先级比 ^~高
  
5)再来测试^~同级之间的优先级
  
   location ^~ 5b.txt {
          return 502
   }
  
   location ^~ /3a/ {
          return 504
   }
  
  
测试结果:
http://192.168.1.80/5b.txt  --------------504
  
结论 :^~优先匹配的是从根开始的匹配
  
6)再来看空格(即什么都不加)与~的优先级比较
  
   location /5b.txt {
          return 502
   }
  
   location ~ /5b.txt {
          return 504
   }
  
测试结果为:
http://192.168.1.80/5b.txt  --------------504
  
结论:空格的优先级比~低
  
优先级排序为:
空格(即不加)
~与*~正则匹配的优先级按先后次序来决定的
^~同级之间的匹配是按照根目录顺序来的
  
------------------------------------------------------------------------------------------
再来看看下面的例子:
  
1)精确匹配,即“=”
location = /images/test.png {
    echo 'config1';
}
  
location  /images/test.png {
    echo 'config2';
}
  
location \/images\/test\.png$ {
    echo 'config3';
}
  
如果此时请求 http://127.0.0.1/images/test.png 输出的内容是config1, 毋容置疑,精确匹配优先级最高!
  
2)精确匹配的特殊情况
location = / {
    index index.html;
}
  
location / {
    echo 'config2';
}
  
此时输入http://127.0.0.1 输出的内容是config2, 怎么精确匹配的优先级不灵了呢?
是这样的,精确匹配还是起作用了,请求目录(非具体文件),nginx会将请求内部定向到index文件,
既此时真正的请求是http://127.0.0.1/index.html, 这是config2则被命中!
所以精确匹配不要用来匹配/
  
3)字符串搜索与正则搜索
location /images/test.png {
    echo 'config1';
}
  
location ^~ /images/ {
    echo 'config2';
}
  
location ~ \/images\/test\.png$ {
    echo 'config3';
}
  
location ~ \/images\/ {
    echo 'config4';
}
  
如果此时请求http://127.0.0.1/images/test.png 输出的内容是config3,正则命中。
(虽然config1为最长匹配的字符串,此时只做记录,后面还要搜索正则匹配,则config3正则匹配命中),
仔细观察可以发现config4也被匹配成功了,但是正则的匹配顺序是按照location的定义顺序匹配的,所以config3命中.
  
4)字符串匹配优先级的提升( ^~ )
location /images/ {
    echo 'config1';
}
  
location ^~ /images/test.png {
    echo 'config2';
}
  
location ~ /images/test\.png$ {
    echo 'config3';
}
  
location ~ \/images\/ {
    echo 'config4';
}
  
如果此时请求 http://127.0.0.1/images/test.png 输出的内容是config2, 首部匹配命中。
(因为字符串匹配是优先搜索的,此时发现config2 为最长的字符串匹配且为^~匹配方式,所以停止搜索正则,直接命中!)
  
所以这里的 ^~ 符号比较特殊,就是为了提高字符串匹配的优先级,优先于正则匹配.
------------------------------------------------------------------
/ 通用匹配,任何请求都会匹配到。
多个location配置的情况下,需要遵循:
首先匹配=
其次匹配^~
再其次按照配置文件的顺序进行正则匹配、
最后是交给/进行通用匹配
注意:当有匹配成功时,立刻停止匹配,按照当前匹配规则处理请求
看看下面匹配规则:
#规则A
location = / {
}
#规则B
location = /login {
}
#规则C
location ^~ /static/ {
}
#规则D
location ~ \.(gif|jpg|png|js|css)$ {
}
#规则E
location ~* \.png$ {
}
#规则F
location !~ \.xhtml$ {
}
#规则G
location !~* \.xhtml$ {
}
#规则H
location / {
}
那么产生的效果如下:
1)访问根目录/, 比如http://localhost/ 将匹配规则A
2)访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
3)访问 http://localhost/static/a.html 将匹配规则C
4)访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而 http://localhost/static/c.png 则优先匹配到规则C
5)访问 http://localhost/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
6)访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
7)访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。
注意:在实际使用中,至少清楚下面匹配规则
1)直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
2)这里是直接转发给后端应用服务器了,也可以是一个静态首页
第一个必选规则:
location = / {
    proxy_pass http://tomcat:8080/index
}
第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
    root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}
第三个规则就是通用规则,用来转发动态请求到后端应用服务器
非静态文件请求就默认是动态请求,自己根据实际把握
毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
    proxy_pass http://tomcat:8080/
}

看看下面几个设置

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
33
34
35
36
37
38
39
40
41
42
43
44
45
# 重写跳转
rewrite  "^/conference/([^/]+)$" /con_detail.php?con_title=$1 last;
rewrite  "^/conference/([^/]+)/$" /con_detail.php?con_title=$1 last;
#屏蔽爬虫
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot")
    {
    return 403;
    }
#favicon.ico不用打日志
   location = /favicon.ico {
      log_not_found off;
      access_log off;
    }
#不允许访问隐藏文件
location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
}
#访问图片,flash文件等不用打日志
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
    expires      7d; #文件返回的过期时间是7天
    access_log off;
}
#访问js和css文件不用打日志
location ~ .*\.(js|css)?$ {
    expires      1d; #文件返回的过期时间是1天
    access_log off;
}
#设置php-cgi
location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    #拦截不存在的php页面请求
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多