Rewrite
Rewrite是Nginx服务器提供的一个重要基本功能。主要的作用是用来实现URL的重写。
Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库。
Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。
Rewrite规则
set
该指令用来设置一个新的变量。
指令 | set $variable value; |
---|---|
默认值 | 无默认值 |
位置 | http, server, location |
用途 | 设置或修改变量的值 |
variable:变量的名称,该变量名称要用"$"作为变量的第一个字符,且不能与Nginx服务器预设的全局变量同名。
value:变量的值,可以是字符串、其他变量或者变量的组合等。
server {
listen 8082;
server_name 127.0.0.1;
location /server {
root /usr/local/nginx/html;
set $name Jack; #设置值
set $age 20;
default_type text/plain;
return 200 $name=$age=$args=$http_user_agent=$host=$document_root; #返回值输出
}
}
访问测试
args表示浏览器中?后面的值,如果加上就会展示出来
200
n
a
m
e
=
name=
name=age=
a
r
g
s
=
args=
args=http_user_agent=
h
o
s
t
=
host=
host=document_root;
上面的例子中输出了":2"
Rewrite常用全局变量
变量 | 说明 |
---|---|
$args | 请求URL中的查询字符串部分,例如 “arg1=value1&args2=value2”。 |
$http_user_agent | 客户端请求头中的User-Agent字段,记录浏览器版本信息等。 |
$host | 访问服务器的Host 头的值,例如 “192.168.101.20:8080”。 |
$document_uri | 当前请求的URI,不包含查询字符串,例如 “/server”。 |
$document_root | 当前请求对应location的root值,未设置时指向Nginx默认目录。 |
$content_length | 请求头中的Content-Length 字段,表示请求体的大小。 |
$content_type | 请求头中的Content-Type 字段,表示请求体的媒体类型。 |
$http_cookie | 客户端的Cookie信息,可通过add_header Set-Cookie 添加。 |
$limit_rate | Nginx对网络连接速率的限制值,0表示不限制。 |
$remote_addr | 客户端的IP地址,例如 “192.168.101.20”。 |
$remote_port | 客户端与服务端建立连接的端口号。 |
$remote_user | 客户端的用户名,需要认证模块支持。 |
$scheme | 访问协议,例如 “http” 或 “https”。 |
$server_addr | 服务端监听的地址。 |
$server_name | 客户端请求到达的服务器名称。 |
$server_port | 客户端请求到达服务器的端口号。 |
$server_protocol | 客户端请求协议的版本,例如 “HTTP/1.1”。 |
$request_body_file | 发给后端服务器的请求体的本地临时文件名。 |
$request_method | 客户端的请求方式,如 “GET” 或 “POST”。 |
$request_filename | 当前请求的资源文件的完整路径名。 |
$request_uri | 当前请求的完整URI,包含请求参数,例如 “/server?id=10&name=lisi”。 |
if指令
该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。
指令 | if |
---|---|
默认值 | 无默认值 |
位置 | http, server, location |
用途 | 根据条件包含或排除配置 |
if ($param){
}
使用"=“和”!="比较变量和字符串是否相等,满足条件为true,不满足为false
if ($request_method = POST){
return 405;
}
判断args是否有值,如果有则返回200 success 。如果第一个条件不满足条件则判断是否为POST请求,如果是则返回405。都不匹配返回200 error
location /testif {
default_type text/plain;
if ($args){
return 200 success;
}
if ($request_method = POST){
return 405;
}
return 200 error;
}
浏览器测试
添加args参数
不添加args参数
使用post请求测试
cmd执行 curl -X POST http://192.168.101.23:8082/testif
POST请求
返回405,对应nginx的判断
用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。
"~"代表匹配正则表达式过程中区分大小写,
"~*"代表匹配正则表达式过程中不区分大小写
"!“和”!*"和上面取相反值,如果匹配上返回false,匹配不上返回true
#$http_user_agent的值中是否包含Mozilla字符串,如果包含返回true
注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}“或者是”;"等字符时,就需要把引号加上。
~* 忽略大小写
!~ 取反 不匹配条件
!~ 不区分大小写*
判断请求的文件是否存在使用"-f"和"!-f".
当使用"-f"时,如果请求的文件存在返回true,不存在返回false。
当使用"!f"时,如果请求文件不存在,但该文件所在目录存在返回true,文件和目录都不存在返回false,如果文件存在返回false
location / {
root html;
default_type text/html;
if (!-f $request_filename){
return 200 '<h1>file not found</h1>';
}
}
访问存在的页面
访问不存在的页面
判断请求的目录是否存在使用"-d"和"!-d"
当使用"-d"时,如果请求的目录存在,if返回true,如果目录不存在则返回false
当使用"!-d"时,如果请求的目录不存在但该目录的上级目录存在则返回true,该目录和它上级目录都不存在则返回false,如果请求目录存在也返回false.
判断请求的目录或者文件是否存在使用"-e"和"!-e"
当使用"-e",如果请求的目录或者文件存在时,if返回true,否则返回false.
当使用"!-e",如果请求的文件和文件所在路径上的目录都不存在返回true,否则返回false
判断请求的文件是否可执行使用"-x"和"!-x"
当使用"-x",如果请求的文件可执行,if返回true,否则返回false
当使用"!-x",如果请求文件不可执行,返回true,否则返回false
break指令
中断当前相同作用域中的其他Nginx配置
- break 指令会中断当前 location 或 if 块中的其他配置指令的执行。
- 位于 break 指令前面的配置指令会生效,而位于其后的配置指令不会被执行。
终止当前的匹配并在本 location 中处理当前 URI: - break 指令会终止当前的匹配过程,而不会再继续其他 location 块的匹配。
- break 会使用修改后的 URI 在当前的 location 块中继续处理,而不是进行重定向。
指令 | break |
---|---|
默认值 | 无默认行为 |
位置 | location block |
用途 | 终止当前 location block 中的后续指令执行 |
location /testbreak {
default_type text/plain;
set $username JACK; #设置username 的初始值
if ($args){ #如果有参数这输出WADE
set $username WADE;
break;
set $username WAYNE;#break后的执行永远都不会被执行
}
add_header username $username;
return 200 $username;
}
测试不加参数访问
添加参数值访问
提示没有对应的文件,因为对testbreak重定向处理了,但是没有相应的文件夹所以提示错误了。
在html下建立testbreak文件夹并添加Index.html(如果没有指定index.html nginx会默认根据当前目录下找index.html)
index.html
<html>
<head>
<title>index.html</title>
</head>
<body>
<h1>testbreak index.html</h1>
</body>
</html>
添加完成后再次添加参数测试
return指令
return 指令在 Nginx 配置中用于立即终止请求处理并返回指定的状态码和可选的响应体。
指令 | return |
---|---|
默认值 | 无默认值 |
位置 | server、location、if |
用途 | 直接返回给客户端指定的HTTP状态码和可选的响应页面或文本 |
返回类型
code:返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理
text:返回给客户端的响应体内容,支持变量的使用
URL:返回给客户端的URL地址
json:返回json格式给客户端
location /testreturn {
default_type application/json;
return 200 '{id:"1",name:"jack"}';
}
url:
location /testreturn {
#default_type application/json;
#return 200 '{id:"1",name:"jack"}';
return https://www.baidu.com;
}
返回状态码:
location /testreturn {
#default_type application/json;
return 302 https://www.baidu.com;
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b86e4158bf964fd6a965adc9ffee109d.png
rewrite指令
该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。
指令 | rewrite |
---|---|
语法 | rewrite regex replacement [flag]; |
默认值 | 无 |
位置 | server block, location block |
用途 | 重写请求的URI或设置变量 |
flag是可选的标志,如last、break、redirect或permanent。
URL和URI的区别:
- URI:统一资源标识符
- URL:统一资源定位符
replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。
location /rewrite {
rewrite ^/rewrite/url\w*$ htts://www.baidu.com; #“^”表示正则表达式的开始 “rewrite”是路径 “url”表示要匹配的字符串,
#“\w”表示匹配任意数字和字母以及下划线 “$”表示以前面的字符结尾 最后写上跳转的地址
rewrite ^/rewrite/(test)\w*$ /$1; #“(test)”表示要匹配的内容, "$1"表示括号里的test,相当于要重写的url "test"就是下面location 中的/test
rewrite ^/rewrite/(demo)\w*$ /$1; #
}
location /test { # 要被跳转的test location
default_type text/plain;
return 200 test_success;
}
location /demo { # 要被跳转的demo location
default_type text/plain;
return 200 demo_success;
}
1.匹配第一个rewrite 跳转到百度
2.匹配第二个rewrite test
3.匹配第三个rewrite demo
flag:用来设置rewrite对URI的处理行为,可选值有如下:
- last
- last 标志告诉 Nginx 在完成当前的重写后,停止执行当前 location 块内的所有后续重写规则,并立即使用新的 URI 进行处理。
(url重写后,马上发起一个新的请求,再次进入server块,重试location匹配,超过10次匹配不到则报500错误,地址栏url不变)
(停止当前这个请求,并根据rewrite匹配的规则重新发起一个请求。新请求又从第一阶段开始执行…)
rewrite ^/rewrite/(test)\w*$ /$1 last;
rewrite ^/rewrite/(demo)\w*$ /$1 last;
break
将此处重写的URI作为一个新的URI,在本块中继续进行处理。该标志将重写后的地址在当前的location块中执行,不会将新的URI转向其他的location块。使用break后会将http://192.168.101.23:8082/rewrite/test后面的路径去重新匹配,“test”或"demo"将作为一个文件夹匹配,默认nginx回去寻找对应文件夹下的index.html
rewrite ^/rewrite/(test)\w*$ /$1 break;
rewrite ^/rewrite/(demo)\w*$ /$1 break;
redirect
-
将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以”http://"或者”https://"开头的情况。
permanent
permanent 标志与 redirect 类似,但它返回 HTTP 301 永久重定向状态码。
永久重定向和临时重定向的区别:
永久重定向:如果要重定向的资源是永久的,就使用permanent 。
临时重定向:如果要重定向的资源是临时的,就使用redirect 。
rewrite_log指令
该指令配置是否开启URL重写日志的输出功能。
指令 | rewrite_log on|off; |
---|---|
默认值 | off |
位置 | http, server, location |
用途 | 开启或关闭重写规则的日志记录,以便于调试和跟踪 |
开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。
location /rewrite {
rewrite_log on;
error_log logs/error.log notice; #需要更改日志级别才能输出到error.log
#rewrite ^/rewrite/\w*$ https://www.baidu.com;
rewrite ^/rewrite/(.*)\w*$ /$1 permanent;
rewrite ^/rewrite/(.*)\w*$ /$1 permanent;
}
Rewrite案例
域名跳转
有三个域名,浏览器输入他们后都会调整到www.home.com域名。例如有下面三个域名
www.home.com | www.home.cn | www.89home.com
修改host文件映射
vim /etc/hosts
127.0.0.1 www.home.com
127.0.0.1 www.home.cn
127.0.0.1 www.89home.com
在/usr/local/nginx/html/home目录下创建一个访问页面
<html>
<title></title>
<body>
<h1>welecome to home!</h1>
</body>
</html>
通过Nginx实现当访问www.访问到系统的首页
server_name 指令在 Nginx 配置中用于定义当前 server 块应响应的域名列表。当一个请求到达 Nginx 时,Nginx 会检查请求的 Host 头部信息,并尝试匹配一个 server 块的 server_name 指令,以确定将请求转发到哪个 server 块进行处理。
server {
listen 80;
server_name www.home.com;
location / {
root html/home;
default_type text/html;
}
index index.html;
}
server {
listen 80;
server_name www.home.cn www.89home.com;
rewrite ^/ http://www.home.com;
通过Rewrite将www.home.cn www.89home.com 跳转到www.home.com首页。
访问测试。访问www.89home.com
.
跳转到www.home.com
域名跳转的过程中携带请求的URI
例如:www.89home.com/findById 跳转后 http://www.home.com/findById
server {
listen 80;
server_name www.home.cn www.89home.com;
#rewrite ^/ http://www.home.com;
rewrite ^(.*) http://www.home.com$1; #^(.*)表示请求的URI $1表示前面括号里面的内容
}
域名镜像
上述案例中,将www.home.cn www.89home.com都能跳转到www.home.com,那么
www.home.com我们就可以把它起名叫主域名,其他两个就是我们所说的镜像域名,当然如果我们不想把整个网站做镜像,只想为其中某一个子目录下的资源做镜像,我们可以在location块中配置rewrite功能,比如:
listen 80;
server_name www.home.cn www.89home.com;
location /user {
rewrite ^/user(.*)$ http://www.home.com$1; #以user开头的都进行跳转
}
location /emp {
default_type text/html;
return 200 '<h1>emp_success</h1>';
}
}
跳转后
独立域名
一个完整的项目包含多个模块,比如购物网站有商品商品搜索模块、商品详情模块已经购物车模块等,那么我们如何为每一个模块设置独立的域名。
http://search.home.com 访问商品搜索模块
http://item.home.com 访问商品详情模块
http://cart.home.com 访问商品购物车模块
对应页面的index.html
搜索页
```html
<html>
<title></title>
<body>
<h1>search page!</h1>
</body>
</html>
购物车页
<html>
<title></title>
<body>
<h1>cart page!</h1>
</body>
</html>
index页
<html>
<title></title>
<body>
<h1>index page!</h1>
</body>
</html>
nginx.conf添加下面的内容:
server {
listen 80;
root html/search;
server_name search.home.com;
rewrite ^(.*) http://www.home.com/search$1 break; #将此处重写的URI作为一个新的URI,在本块中继续进行处理。
#该标志将重写后的地址在当前的location块中执行,不会将新的URI转向其他的location块
}
server {
listen 80;
root html/item;
server_name item.home.com;
rewrite ^(.*) http://www.home.com/item$1 break;
}
server {
listen 80;
root html/cart;
server_name cart.home.com;
rewrite ^(.*) http://www.home.com/cart$1 break;
}
测试
search.home.com
item.home.com
cart.home.com