0%

nginx学习笔记:rewrite重定向规则

写在前面

nginx的rewrite规则就是使用正则匹配请求的url,然后根据定义的规则进行重写和改变,从一个 location 跳转到另一个 location。它依赖ngx_http_rewrite_module模块来支持url重写功能(标准模块,默认已经安装)。

这则笔记主要包括以下内容:

rewrite规则:

  • 正则基础

  • 常用变量

  • flag

rewrite常见用法:

  • 域名重定向

  • https跳转

  • 域名访问二级目录

  • 动静分离

  • 防盗链

rewrite规则

格式:rewrite regex replacement [flag]

说明:rewrite配置可以在server、location以及if配置段内生效,主要包括以下三个部分:

* regex是用于匹配URI的正则表达式,其不会匹配到$host(域名);

* replacement是目标跳转的URI,这里涉及到变量相关的知识;

* flag,用来设置rewrite对URI的处理行为,其中有break、last、rediect、permanent;

正则基础

rewrite规则的第一部分是一个正则表达式,用来匹配规则。常用的符号如下:

大小写匹配

~ 区分大小写匹配;

~* 不区分大小写匹配;

!~!~*分别取反,意思是区分大小写不匹配及不区分大小写不匹配;

文件及目录匹配

-f和!-f用来判断是否存在文件;

-d和!-d用来判断是否存在目录;

-e和!-e用来判断是否存在文件或目录;

-x和!-x用来判断文件是否可执行

常用变量

第二部分是uri,这部分涉及到变量相关的知识。

url和uri的区别:

URI:Universal Resource Identifier ,通用资源标识符,用于对网络中的各种资源进行标识,由存放资源的主机名、片段标志符和相对的URI三部分组成。存放资源的主机名一般由传输协议(Scheme)、主机和资源路径三部分组成;片段标识符指向资源内容的具体元素、相对URI表示资源在主机上的相对路径。一般格式为:Scheme://[用户名][:密码]@主机名[:端口号][/资源路径]

URL:Uniform Resource Location,统一资源定位符,是用于在Internet中描述资源的字符串,是URI的子集,主要包括传输协议(Scheme)、主机(IP、端口号或者域名)和资源集体地址(目录或文件名)等三部分,一般格式为:scheme://主机名[:端口号]/[资源路径]

在nginx当中,默认预设了一些常用变量,如下:

变量 说明
$args 请求中的参数,如www.123.com/1.php?a=1&b=2的$args就是a=1&b=2
$content_length HTTP请求信息里的”Content-Length”
$conten_type HTTP请求信息里的”Content-Type”
$document_root nginx虚拟主机配置文件中的root参数对应的值
$document_uri 当前请求中不包含指令的URI,如www.123.com/1.php?a=1&b=2的$document_uri就是1.php,不包含后面的参数
$host 主机头,也就是域名
$http_user_agent 客户端的详细信息,也就是浏览器的标识,用curl -A可以指定
$http_cookie 客户端的cookie信息
$limit_rate 如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_addr 客户端的公网ip
$remote_port 客户端的port
$remote_user 如果nginx有配置认证,该变量代表客户端认证的用户名
$request_body_file 做反向代理时发给后端服务器的本地资源的名称
$request_method 请求资源的方式,GET/PUT/DELETE等
$request_filename 当前请求的资源文件的路径名称,相当于是$document_root/$document_uri的组合
$request_uri 请求的链接,包括$document_uri和$args
$scheme 请求的协议,如ftp,http,https
$server_protocol 客户端请求资源使用的协议的版本,如HTTP/1.0,HTTP/1.1,HTTP/2.0等
$server_addr 服务器IP地址
$server_name 服务器的主机名
$server_port 服务器的端口号
$uri 和$document_uri相同
$http_referer 客户端请求时的referer,通俗讲就是该请求是通过哪个链接跳过来的,用curl -e可以指定

flag 标记

用来设置rewrite对URI的处理行为,其中有break、last、rediect、permanent,下面逐一介绍。

break和last

两个指令用法相同,但含义不同,需要放到rewrite规则的末尾,用来控制重写后的链接是否继续被nginx配置执行(主要是rewrite、return指令)。

使用last和break实现URI重写,浏览器地址栏不变。但两者有所区别:

  • 使用alias指令必须用last标记;使用proxy_pass指令时,需要使用break标记;

  • Last标记在本条rewrite规则执行完毕后,会对其所在server{}标签重新发起请求,而break标记则在本条规则匹配完成后,终止匹配。

  • 当rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location;

  • 当rewrite规则在location{}

    • 遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行;

    • 遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头开始执行所有规则,哪个匹配执行哪个。

redirect和permanent

redirect和permanent都可以用来做重定向,两者的区别在于,前者为临时重定向(302),而后者是永久重定向(301),对于用户通过浏览器访问,这两者的效果是一致的。但是,对于搜索引擎蜘蛛爬虫来说就有区别了,使用301更有利于SEO。所以,建议replacemnet是以http://或者https://开头的flag使用permanent。

if语句

重写规则时,还需要了解if语句,格式如下:

1
if (条件判断) { 具体的rewrite规则 }

条件判断语句由Nginx内置变量、逻辑判断符号和目标字符串三部分组成。其中,

  • 内置变量是Nginx固定的非自定义的变量,如,$request_method, $request_uri等;

  • 逻辑判断符号,有=, !=, ~, ~*, !~, !~* !表示相反的意思,~为匹配符号,它右侧为正则表达式,区分大小写,而~*为不区分大小写匹配;

  • 目标字符串可以是正则表达式,通常不用加引号,但表达式中有特殊符号时,比如空格、花括号、分号等,需要用单引号引起来;

return语句

return语句一般用于对请求的客户端直接返回响应状态码、字符串或者url链接,可以使用在server、location以及if配置中。

直接返回状态码

1
2
3
4
5
6
7
8
9
10
11
server {
.....

if ($request_uri ~ "\.htpasswd|\.bak")
{
return 404;
rewrite /(.*) /aaa.txt; //该行配置不会被执行。
}
//如果下面还有其他配置,会被执行。
.....
}

返回字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   示例1:反馈字符串
server{
listen 80;
server_name www.test.com;
return 200 "hello";
}
//说明:如果要想返回字符串,必须要加上状态码,否则会报错。

示例2:支持json数据
location ^~ /test {
default_type application/json ;
return 200 '{"name":"test","id":"100"}';
}

示例3:反馈变量
location /test {
return 200 "$host $request_uri";
}

返回url

1
2
3
4
5
6
7
示例6:
server{
listen 80;
server_name www.test.com;
return http://www.test.com/123.html; //注意:return后面的url必须是以http://或者https://开头的。
rewrite /(.*) /abc/$1; //该行配置不会被执行。
}

rewrite 常见用法

域名重定向

示例1(不带if条件判断的):

1
2
3
4
5
6
server{
listen 80;
server_name www.test.com;
rewrite /(.*) http://www.test.com/$1 permanent;

}

示例2(带if条件判断的):

1
2
3
4
5
6
7
8
9
server{
listen 80;
server_name www.test.com test.com;
if ($host != 'www.test.com')
{
rewrite /(.*) http://www.test.com/$1 permanent;
}

}

http跳转到https

1
2
3
4
5
6
server{
listen 80;
server_name www.test.com;
rewrite /(.*) https://www.test.com/$1 permanent;

}

域名访问二级目录

1
2
3
4
5
6
server{
listen 80;
server_name bbs.test.com;
rewrite /(.*) http://www.test.com/bbs/$1 last;

}

静态请求分离

1
2
3
4
5
6
7
8
9
server{
listen 80;
server_name www.test.com;
if ( $uri ~* 'jpg|jpeg|gif|css|png|js$')
{
rewrite /(.*) http://test-img.com/$1 permanent; //注意:test-img.com指的是另一个域名,专门用来存放静态资源
}

}

防盗链

1
2
3
4
5
6
7
8
9
10
11
12
13
server{
listen 80;
server_name www.aminglinux.com;
location ~* ^.+.(jpg|jpeg|gif|css|png|js|rar|zip|flv)$
{
valid_referers none blocked server_names *.test.com test.com;
if ($invalid_referer)
{
rewrite /(.*) http://test-img.com/images/forbidden.png;
}
}

}

说明:

  • *这里是通配,跟正则里面的*不是一个意思;

  • none指的是referer不存在的情况(curl -e 测试);

  • blocked指的是referer头部的值被防火墙或者代理服务器删除或者伪装的情况,该情况下,referer头部的值不以http://或者https://开头(curl -e 后面跟的referer不以http://或者https://开头)。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!