nginx有两层指令来匹配请求 URL
:
域名、ip和端口
来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。请求uri
来做第二层匹配。server {
listen 81; # 监听的端口
server_name localhost; # 域名或ip
location / { # 访问路径配置
return 400;
}
location /xx/xx { # 访问路径配置
return 402;
}
}
server {
listen 82; # 监听的端口
server_name localhost; # 域名或ip
location / { # 访问路径配置
return 401;
}
}
注解:每一个端口为一个Server,用于做不同的事情。
补充知识点:
域名访问
1) windows
C:\Windows\System32\drivers\etc\hosts 在这个目录下增加域名与ip的映射
2) linux
/etc/hosts 在这个目录下增加域名和ip的映射关系
2 基于域名的例子
server {
listen 82;
server_name www.liyong.f.com;
location / {
return 401;
}
}
server {
listen 83;
server_name www.liyong.s.com;
location / {
return 402;
}
}
然后再服务客户端配置域名ip映射,windows和linux配置文件不同参考上面的路径。
访问:http://www.liyong.s.com:83/ http://www.liyong.f.com:82/
每个server块中可以包含多个location块。location块的主要作用是,基于nginx服务器接收到的客户端发送过来的请求uri
(例如, server_name/uri-string
),对除虚拟主机名称(也可以是IP别名)之外的字符串(前例中“/uri-string
”部分)进行匹配,对特定的请求进行处理。
地址定向、数据缓存和应答控制等功能都是在这部分实现。许多第三方模块的配置也是在location块中提供功能。
location [ = | ~ | ~* | ^~ ] /uri { #配置location可以配置的属性 } #[] 里面的意思是多种写法 | 表示或 不要错误的理解为location的配置还有[] 里面配一串之类的 实际配置 location =, location ^~ 是这样的
location匹配参数解释
参数 | 匹配方式 | 匹配模式 | 说明 | 注意事项 |
---|---|---|---|---|
= |
精准匹配 | 普通字符串匹配 | 用于标准uri 前,要求请求字符串与uri精准匹配,成功则立即处理,nginx停止搜索其他匹配。 |
|
~ |
正则匹配 | 正则表达式匹配 | 用于正则uri ,表示uri包含正则表达式,并且区分大小写。 |
如果uri包含正则表达式,就必须要使用“~”或者“~*”标识。 |
~* |
正则表达式匹配 | 用于正则uri ,表示uri包含正则表达式,并且不区分大小写。 |
||
^~ |
带参前缀匹配 (短路匹配) | 普通字符串匹配 | 用于标准uri 前,并要求一旦匹配到就会立即处理,不再去匹配其他的正则URI,一般用来匹配目录。 |
|
空 |
普通前缀匹配 | 普通字符串匹配 | location后没有参数直接跟着标准uri ,表示前缀匹配,代表跟请求中的uri从头开始匹配。 |
location匹配顺序
location 的匹配并不完全按照其在配置文件中出现的顺序来匹配,请求URI 会按如下规则进行匹配,优先级从高到低依次为(序号越小优先级越高
):
1. location = # 精准匹配,精准匹配成功则会立即停止其他类型匹配;
2. location ^~ # 带参前缀匹配。如果是带有 ^~ 的前缀匹配,匹配成功则立即停止其他类型匹配;如果是普通前缀匹配(不带参数 ^~ )成功则会暂存,继续查找正则匹配;
3. location ~ # 正则匹配(区分大小写)。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;
4. location ~* # 正则匹配(不区分大小写)
5. location /a # 普通前缀匹配,优先级低于带参数前缀匹配。所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数 ^~ )结果。普通字符串匹配则无视顺序,只会选择最精确的匹配。
6. location / # 任何没有匹配成功的,都会匹配这里处理
1 通用匹配
相当于是兜底处理,所有的规则匹配不成功就会走兜底处理。
server {
listen 82;
server_name www.liyong.f.com;
# 因为所有的地址都以 /开头,所以这条规则将匹配到所有请求,比如访问 / 和 /testOrder , 则 / 匹配 /data,/test也匹配,
location / { #作为最后的匹配项
return 401;
}
location /testOrder { #普通前缀匹配
root html;
index index.html
}
}
访问:
http://www.liyong.f.com:82/data,http://www.liyong.f.com:82/test 都是401
访问testOrder 会走下面的匹配 其实它也是能匹配上/的,但是/testOrder优先级更高就会去服务器相对路径/html/testOrder/寻找资源。
同时通过上面的例子也验证了,匹配与location的书写顺序无关。如果有关就会被/ 先匹配。
2 普通前缀匹配
就是根据普通路径进行匹配,非等值匹配匹配最长的路径。
server {
listen 82;
server_name www.liyong.f.com;
location /doc {
return 402;
}
location /docu {
return 500;
}
}
访问:http://www.liyong.f.com:82/document
说明
:前缀匹配下,返回最长匹配的 location,与 location 所在配置文件中的顺序无关。
3 正则匹配
3.1 正则匹配与普通匹配
location ~ ^/proxy { #正则匹配
return 500;
}
location /proxy { #普通匹配
return 410;
}
访问:http://www.liyong.f.com:82/proxy 可以发现 正则匹配的优先级更高
3.2 正则匹配与正则匹配
location ~ ^/proxy[0-9]+ {
return 500;
}
location ~ ^/proxy[0-9]+ {
return 401;
}
访问:http://www.liyong.f.com:82/proxy114445
但是如果我们交换顺序:
location ~ ^/proxy[0-9]+ {
return 401;
}
location ~ ^/proxy[0-9]+ {
return 500;
}
访问:http://www.liyong.f.com:82/proxy114445
说明
:通过上面的案例可以看到,如果路径满足多个正则,则配置顺序决定了优先级,在前面location会匹配成功。
3.3 区分大小写的正则匹配
server {
listen 82;
server_name www.liyong.f.com;
location ~ /doc{
return 401;
}
location ~* /doc { #正则匹配区分大小写
return 402;
}
}
访问: www.liyong.f.com:82/DOC 402
访问 :www.liyong.f.com:82/doc 401
4 带参前缀匹配
4.1 多个带参前缀与正则的优先级
server {
listen 82;
server_name www.liyong.f.com;
location ^~ /doc {
return 401;
}
location ^~ /document {
return 402;
}
location ~ /document {
return 500;
}
}
http://www.liyong.f.com:82/document
说明
:都是带参的情况下也是会匹配最长路径,但是这点和正则不同,正则是谁先成功就就走谁。而且我们后面还配了一个路径更长的正则匹配确没有走,证实了带参前缀匹配 ^~ 命中以后会再搜寻其他带参前缀匹配,不会搜索正则匹配。
5 精准匹配
5.1 多个精准匹配
location = /doc {
return 401;
}
location = /document {
return 402;
}
精准匹配:
只有访问http://www.liyong.f.com:82/doc,http://www.liyong.f.com:82/document 才能正确处理。也就是路径必须一模一样。
5.2 精准匹配与带参前缀匹配
location ^~ /document {
return 402;
}
location = / {
return 400;
}
location = /document {
return 401;
}
访问:/document 返回401 所以精准匹配的优先级高于带参匹配
1 第一个必选规则
直接匹配网站根
,通过域名访问网站首页比较频繁,使用这个会加速处理,比如说官网。location = /index.html {
root html
index index.html index.htm
}
location = / {
root html
index index.html index.htm
}
2 第二个必选规则
处理静态文件请求,这是nginx作为http服务器的强项
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* .(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
3 通用匹配,作为兜底
location / {
return 500;
}
1 匹配问号后的参数
请求 URI 中问号后面的参数是不能在 location 中匹配到的,这些参数存储在 $query_string 变量中,可以用 if 来判断。
location /idx {
if ($query_string ~* ".*id.*" ) {
return 500;
}
return 401;
}
访问:http://www.liyong.s.com:83/idx?jdid 500
访问:http://www.liyong.s.com:83/idx?xx 401
2 URI 结尾带不带/
1)在location
中配置的URI
有没有 /
都没有影响。也就是说 /user/
和 /user
是一样的。
2)如果浏览中发送的 URI 结构是 https://domain.com/
的形式,尾部有没有 /
都不会造成重定向。因为浏览器在发起请求的时候,默认加上了 /
。虽然很多浏览器在地址栏里也不会显示 /
。这一点,可以访问baidu验证一下。
3)如果浏览中发送的 URI 结构是 https://domain.com/``some-dir/
。尾部如果缺少 /
将导致重定向。因为根据约定,URI 尾部有 /
表示目录,没有 /
表示文件。
a. 所以访问 /some-dir/
时,服务器会自动去该目录下找对应的默认文件。
b. 如果访问 /some-dir
的话,服务器会先去找 some-dir
文件,找不到的话会将 some-dir
当成目录,重定向到 /some-dir/
,去该目录下找默认文件。
rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标记位实现URL重写以及重定向。
比如:更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求。
server{},location{},if{}
中,并且默认只能对域名后边的除去传递的参数外的字符串
起作用。rewrite 跳转实现
nginx 是通过 ngx_http_rewrite_module
模块支持 url 重写、支持 if 条件判断,但不支 持 else。
另外该模块需要 PCRE
支持,应在编译 nginx 时指定 PCRE 支持,默认已经安装。
根据相关变量重定向和选择不同的配置,从一个 location 跳转到另一个 location,不过这样 的循环最多可以执行 10
次,超过后 nginx 将返回 500 错误。
rewrite 执行顺序
执行 server 块里面的 rewrite 指令。
执行 location 匹配。
执行选定的 location 中的 rewrite 指令。
flag标记说明
last
:本条规则匹配完成后,不终止重写后的url匹配,一般用在 server
和 if
中。break
:本条规则匹配完成即终止,终止重写后的url匹配,一般使用在 location
中。redirect
:返回302
临时重定向,浏览器地址会显示跳转后的URL地址。permanent
:返回301
永久重定向,浏览器地址栏会显示跳转后的URL地址。1 重新定向到nginx中的路径
server {
listen 82;
server_name www.liyong.f.com;
location / {
# 判断主机名为www.itxh.com则重写为www.newitxh.com
if ($host = 'www.liyong.f.com'){
rewrite ^/(.*)/(.*)$ /demo/$2 permanent; #这里$2 表示第二个括号的内容
}
root html;
index index.html index.htm;
}
location /demo/aaa {
alias html;
index index.html index.htm;
}
}
访问:http://www.liyong.f.com:82/test/aaa 可以看到被重新定向
结合这个uri解释一下$2 这个$2就是aaa,如果我们写$1则值是test
拓展:
location /test/ {
# 判断主机名为www.itxh.com则重写为www.newitxh.com
if ($host = 'www.liyong.f.com'){
rewrite ^/(.*)/(.*)$ /demo/$2 permanent;
}
root html;
index index.html index.htm;
}
location /demo/aaa {
alias html;
index index.html index.htm;
}
这个时候我们访问路径:http://www.liyong.f.com:82/test/test/aaa 才能狗重定向到 /demo/aaa 。由此我们验证了rewrite 后面的正则表达式^/(.)/(.)$是不包含location的路径的,是除去location路径向后匹配。就比如http://www.liyong.f.com:82/test/aaa/bbb被重定向以后是http://www.liyong.f.com:82/demo/bbb
2 基于域名的跳转
rewrite ^/(.*)$ http://www.liyong.demo.com/$1 permanent;
3 结合ip 或者其它内置变量使用(以ip为例子)
错误配置并且浏览器会缓存重定向,如果你修改了nginx配置发现依然重定向到之前的地址,可以清空浏览缓存试试。
server {
listen 82;
server_name www.liyong.f.com;
set $is_rewrite false;
if ($remote_addr = '15.195.14.17') {
set $is_rewrite true;
}
if ($is_rewrite = true) {
rewrite (.+) /demo/aaa permanent ;
}
location /test/ {
if ($host = 'www.liyong.f.com'){
add_header X-Remote-Addr $remote_addr;
rewrite ^/(.*)/(.*)$ /demo/$2 permanent;
}
root html;
index index.html index.htm;
}
location /demo/aaa {
alias html;
index index.html index.htm;
}
}
这个配置会导致死循环,这个是实战中一定要注意的,但是实际上重定向超过一定次数也就不会再发送请求到nginx了,会报错误重定向次数过多
正确的配置:
server {
listen 80;
server_name localhost;
# 设置变量为$rewrite,变量值为boolean类型的true
set $rewrite true;
# 当客户端IP为15.195.14.17时,将$rewrite变量值设为false
if ($remote_addr = "15.195.14.17"){
set $rewrite false;
}
# 当变量值为true时,进行rewrite重写,将域名后面的路径重写为/weihu.html
if ($rewrite = true){
rewrite (.+) /weihu.html;
}
# 精确匹配/weihu.html请求
location = /weihu.html {
# 看到400页面,就表示重定向成功了
return 400;
}
location / {
return 401;
}
}
4 基于参数匹配的跳转
4.1
server {
listen 80;
server_name localhost;
#正则匹配成功就跳转
if ($request_uri ~ ^/100-(100|200)-(\d+).html$) {
rewrite (.+) http://www.liyong.com permanent;
}
location / {
return 400;
}
}
4.2
server {
listen 80;
server_name localhost;
location ~* ^/abc/123.html {
rewrite (.+) http://www.liyong.com permanent
}
location / {
return 400;
}
}
4.3
server {
listen 80;
server_name localhost;
location ~* ^/abc/123.html {
rewrite (.+) http://www.liyong.com permanent
}
location / {
return 400;
}
}