文章目录
- 一、Rewrite的相关配置指令
- (一)set 指令
- (二)if 指令
- (三)break 指令
- (四)return 指令
- (五)rewrite 指令
- (六)rewrite_log 指令
- 二、Rewrite的应用场景
- (一)域名跳转
- (二)域名镜像
- (三)独立域名
- (四)合并目录
Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。
主要的作用是用来实现URL的重写。
注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务之前,需要安装PCRE库(正则表达式库)。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置(nginx默认将该模块编译进来)。
地址重写 & 地址转发
重写和转发的区别:
- 地址重写,浏览器地址会发生变化,而地址转发则不变。
- 一次地址重写会产生两次请求,而一次地址转发只会产生一次请求。
- 地址重写到的页面必须是一个完整的路径而地址转发则不需要。
- 地址重写因为是两次请求所以request范围内属性不能传递给新页面而地址转发因为是一次请求所以可以传递值。
- 地址转发速度快于地址重写。
一、Rewrite的相关配置指令
(一)set 指令
该指令用来设置一个新的变量
语法 | set $variable value; |
默认值 | - |
位置 | server、location、if |
variable:变量的名称,该变量名称要用“$”作为变量的第一个字符,且不能与Nginx的内置全局变量同名
value:变量的值,可以是字符串,其他变量或者变量的组合等
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/set.conf
server {
listen 81;
server_name localhost;
location /server {
set $name TOM;
set $age 18;
default_type text/plain;
return 200 $name=$age;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
效果:
Rewrite常用全局变量
变量 | 说明 |
$args | 变量中存放了请求URL中的请求参数。比如 http://192.168.1.10/server?arg1=value1&arg2=value2 中的”arg1=value1&arg2=value2”,功能和$query_string一样 |
$http_user_agent | 变量存储的是用户访问服务的代理信息(如果通过浏览器访问,记录的是浏览器的相关版本信息) |
$host | 变量存储的是访问服务器的 server_name 值 |
$document_uri | 变量存储的是当前访问地址的URI。比如 http://192.168.1.10/server?id=10&name=zhangsan 中的“/server”,功能和$uri一样 |
$document_root | 变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带的html目录所在位置 |
$content_length | 变量存储的是请求头中Content-Length的值(头信息的内容长度) |
$content_type | 变量存储的是请求头中的Content-Type的值(mime类型) |
$http_cookie | 变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie 'cookieName=cookieValue’来添加cookie数据 |
$limit_rate | 变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制 |
$remote_addr | 变量中存储的是客户端的IP地址 |
$remote_port | 变量中存储了客户端与服务端建立连接的端口号 |
$remote_user | 变量中存储了客户端的用户名,需要有认证模块才能获取 |
$scheme | 变量中存储了访问协议 |
$server_addr | 服务端的地址 |
$server_port | 客户端请求到达服务端的端口号 |
$server_protocol | 客户端请求协议的版本,比如"HTTP/1.1" |
$request_body_file | 发给后端服务器的本地文件资源名称 |
$request_method | 客户端的请求方式,比如"GET"、"POST"等 |
$request_uri | 当前请求的URI,并且携带请求参数,比如 http://192.168.1.10/server?id=10&name=zhangsan 中的"/server?id=10&name=zhangsan";$args 和 $document_uri的结合 |
上述参数还可以在日志中通过 log_format 指令使用
(二)if 指令
该指令用来支持条件判断,并根据判断结果选择不同的Nginx配置
语法 | if (condition) {…} |
默认值 | - |
位置 | server、location |
condition为判定条件,可以支持以下写法:
- 变量名。如果变量名对应的值为空字符串或“0”,if都判断为false,其他条件为true。
if ($param){
}
【例 】
案例一:
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location /testif {
set $username ''; # 设置一个变量,变量名为username,值为空
default_type text/plain;
if ($username){ # 因为username变量为空,所以if判断为false
return 200 $username; # 判断条件为true,页面上返回该变量的值
}
return 200 'param is empty'; # 判断条件为false,页面上返回字符串 “param is empty”
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
效果:
案例二:
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location /testif {
set $username 'xiaoming';
default_type text/plain;
if ($username){
return 200 $username;
}
return 200 'param is empty';
return 200 $args;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
效果:
案例三:
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location /testif {
default_type text/plain;
if ($args){
return 200 success;
}
return 200 error;
}
}
# 传递参数返回success,没有传递参数返回error
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
效果:
- 使用“=”和“!=”比较变量和字符串是否相等,满足条件为true,不满足为false
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location /testif {
default_type text/plain;
if ($args){
return 200 success;
}
if ($request_method = POST){ # 要想执行到第二个if,必须上面的if不满足;即没有传递参数(或参数为0)且客户端请求方式为POST,返回405状态码
return 405;
}
return 200 error;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
效果:
因为没有传递参数且请求方式为GET,所以返回error
因为传递参数,所以返回success
浏览器不便于直接模拟POST请求,使用命令行模拟;因为不带参数且请求方式为POST,所以返回405
注意:此处和JAVA不太一样的地方是字符串不需要添加引号,并且等号和不等号前后都需要加空格。
- 使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用 “~” ,"~*","!~","!~*"来连接。
“~” :代表匹配正则表达式过程中区分大小写;
"~*" :代表匹配正则表达式过程中不区分大小写;
"!~“和”!~*": 刚好和上面取相反值,如果匹配上返回false,匹配不上返回true。
注意:正则达式字符串一般不需要加引号,但是字符串中如果包含"}“或者是”;"等字符时,就需要加上引号。
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location /testif {
default_type text/plain;
if ($http_user_agent ~* firefox){ # 如果客户端浏览器为火狐,则页面返回字符串“ TRUE:客户端版本具体信息 ”,否则返回 “ FALSE:客户端版本具体信息 ”
return 200 TRUE:$http_user_agent;
}
return 200 FALSE:$http_user_agent;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
IE浏览器测试
火狐浏览器测试
- 判断请求的文件是否存在使用"-f"和"!-f"
if (-f $request_filename){
...
}
if (!-f $request_filename){
...
}
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/if.conf
server {
listen 81;
server_name localhost;
location / {
root /usr/share/nginx/html;
default_type text/html;
if (!-f $request_filename){
return 200 '<h1>sorry,file not found</h1>';
}
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
- 判断请求的目录是否存在使用"-d"和"!-d"
- 判断请求的目录或者文件是否存在使用"-e"和"!-e"
- 判断请求的文件是否可执行使用"-x"和"!-x"
(三)break 指令
该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。并且break还有另外一个功能就是终止当前的匹配并把当前的URI在本location进行重定向访问处理。
语法 | break; |
默认值 | - |
位置 | server、location、if |
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/break.conf
server {
listen 82;
server_name localhost;
root /usr/share/nginx/html;
location /testbreak {
default_type text/plain;
set $username TOM;
if ($args){
set $username JERRY;
break;
set $username ROSE;
}
add_header username $username; # 将改变量加入到头信息中
return 200 $username;
}
}
[root@nginx ~]# mkdir /usr/share/nginx/html/testbreak
[root@nginx ~]# echo "testbreak/index.html" > /usr/share/nginx/html/testbreak/index.html
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
结果:
没有传递参数,所以没有进入if条件,那么输出结果为TOM
任意传递参数后,因为进入if条件中,所以此时username为JERRY且有break所以后面的ROSE并不会赋值给变量username。
可以看到,break先是实现了301永久跳转
(四)return 指令
该指令用于完成对请求的处理,直接向客户端返回。在return后的所有Nginx配置都是无效的。
语法 | return code [text]; return code URL; return URL; |
默认值 | - |
位置 | server、location、if |
code:为返回客户端的HTTP状态代理。可以返回的状态码为0~999的任意HTTP状态代理
text:为返回给客户端的响应体内容,支持变量的使用
URL:为返回给客户端的URL的值
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/testreturn.conf
server {
listen 82;
server_name localhost;
location /testreturn1 {
return 502;
}
location /testreturn2 {
default_type text/plain;
return 200 'It is a test';
}
location /testreturn3 {
default_type text/html;
return 200 '<h1>It is a test</h1>';
}
location /testreturn4 {
default_type application/json;
return 200 '{id:1,name:"zhangsan"}';
}
location /testreturn5 {
return https://www.baidu.com;
}
}
测试:
(五)rewrite 指令
该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。
语法 | rewrite regex replacement [flag] |
默认值 | - |
位置 | server、location、if |
regex:用来匹配URI的正则表达式
replacement:匹配成功后,用于替换URI中被截取内容的字符串。 如果该字符串是以”http://“或”https://“开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。
【例 】
[root@nginx ~]# vim /etc/nginx/conf.d/rewrite.conf
server {
listen 82;
server_name localhost;
location /rewrite {
rewrite ^/rewrite/url\w*$ https://www.baidu.com;
rewrite ^/rewrite/(test)\w*$ /$1;
rewrite ^/rewrite/(demo)\w*$ /$1;
}
location /test{
default_type text/plain;
return 200 test;
}
location /demo{
default_type text/plain;
return 200 demo;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
测试;
第一个rewrite指令效果
第二个rewrite指令效果
第三个rewrite指令效果
flag:用来设置rewrite对URI的处理行为,可选值如下:
- last:终止继续在本location块中处理接收到的URI,并将此处重写的URI作为一个新的URI,使用各location块进行处理。该标志将重写后的URI重写在server块中执行,为重写后的URI提供了转入到其他location块的机会。
[root@nginx ~]# vim /etc/nginx/conf.d/rewrite.conf
server {
listen 82;
server_name localhost;
location /rewrite {
rewrite ^/rewrite/(testlast)\w*$ /$1 last; # 访问 192.168.126.41:82/rewrite/testlastxxxx 那么会转发到其他匹配/testlast的location去处理
}
location /testlast{
default_type text/plain;
return 200 test;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
- break:将此处重写的URI作为一个新的URI,在本块中继续进行处理。该标志将重写后的地址在当前的location块中执行,不会将新的URI转向其他的location块。
[root@nginx ~]# vim /etc/nginx/conf.d/rewrite.conf
server {
listen 82;
server_name localhost;
location /rewrite {
rewrite ^/rewrite/(testbreak)\w*$ /$1 break; # 访问 192.168.126.41:82/rewrite/testlastxxxx 那么会在本location块中进行处理
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
因为在该location块中未指明该文件的位置,默认去安装目录下也没有此文件
- redirect:将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以”http://“或”https://“开头的情况。
[root@nginx ~]# vim /etc/nginx/conf.d/rewrite.conf
server {
listen 82;
server_name localhost;
location /rewrite {
rewrite ^/rewrite/(testredirect)\w*$ /$1 redirect; # 访问 192.168.126.41:82/rewrite/testlastxxxx 那么会在本location块中进行处理
}
location /testredirect{
default_type text/plain;
return 200 testdirect;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
在浏览器输入 192.168.126.41:81/rewrite/testredirectabcdefg 后会被临时重定向,所以浏览器URL栏显示为 192.168.126.41:81/testredirect
- permanent:将重写后的URI返回给客户端,状态码为301,指明时永久重定向URI,主要用在replacement变量不是以”http://“或”https://“开头的情况。
[root@nginx ~]# vim /etc/nginx/conf.d/rewrite.conf
server {
listen 82;
server_name localhost;
location /rewrite {
rewrite ^/rewrite/(testpermanent)\w*$ /$1 permanent;
}
location /testpermanent{
default_type text/plain;
return 200 testpermanent;
}
}
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
在浏览器输入 192.168.126.41:81/rewrite/testpermanentabcde 后会被永久重定向,所以浏览器URL栏显示为 192.168.126.41:81/testpermanent
(六)rewrite_log 指令
该指令配置是否开启URL重写日志的输出功能
语法 | rewrite_log on|off |
默认值 | rewrite_log off |
位置 | http、server、location、if |
开启后,URL重写的相关日志将以notice级别输出到err_log指令配置的日志文件汇总。
rewrite_log on;
error_log /path/to/error.log notice;
二、Rewrite的应用场景
(一)域名跳转
当输入 www.jd.com ,便可以访问京东网站,同样也可以输入 www.360buy.com 同样访问到京东网站。京东刚开始的时候域名就是 www.360buy.com ,后面由于某些原因将域名更换为 www.jd.com 。虽然说域名改变了,但是对于以前只记住 www.360buy.com 域名的用户来说,如何将这部分用户也迁移到 www.jd.com 新域名上来。此时,就可以使用Nginx中Rewrite的域名跳转功能来实现。
【例 】
三个域名
[root@nginx ~]# vim /etc/nginx/conf.d/hosts.conf
server {
listen 80;
server_name www.test.com;
location / {
default_type text/html;
return 200 '<h1>It is test!';
}
}
server {
listen 80;
server_name www.test1.com www.test2.cn;
rewrite ^/ http://www.test.com;
}
效果:
但是这样跳转也存在一定的问题,比如,访问 www.test1.com/user/login 会跳转到 www.test.com 而不会跳转到 www.test.com/user/login ,所以,需要对rewrite指令中的regex(regex:用来匹配URI的正则表达式)做进一步处理。
[root@nginx ~]# vim /etc/nginx/conf.d/hosts.conf
server {
listen 80;
server_name www.test.com;
location / {
default_type text/html;
return 200 '<h1>It is test!';
}
}
server {
listen 80;
server_name www.test1.com www.test2.cn;
rewrite ^(.*) http://www.test.com$1;
}
那么,此时如果访问 www.test1.com/user/login 或 www.test2.cn/user/login 会跳转到 www.test.com/user/login
(二)域名镜像
镜像网站指定是将一个完全相同的网站分别放置到几台服务器上,并分别使用独立的URL进行访问。其中一台服务器上的网站叫主站,其他的为镜像网站。镜像网站和主站没有太大的区别,可以把镜像网站理解为主站的一个备份节点。可以通过镜像网站提供网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载、可以解决网络宽带限制、封锁等。
当web项目开发完成以后,会将它部署在一台服务器上对外提供服务,如果使用的是单节点的方式对外提供服务就会存在一些缺点。比如:高可用性较差(该节点出现故障,整个web项目都无法对外界提供服务)、无法应对比较高的并发量等。为了解决这些问题比较常见的做法是通过集群(搭建多个节点提供服务)方式来部署web项目在多个节点上,那这个时候其中一台节点就称为主站,其他的节点可以称为镜像网站(镜像网站也可以理解为主站的备份节点,那么就提高了高可用性,其中一台节点挂掉,其他的节点可以正常对外提供服务)。主站和镜像网站节点中的内容应该是一样的,提供相同的服务。并且还可以将这些节点分布在不同的地区同时提高不同地区的响应速度,同时,可以将用户的请求分发在不同的节点上,实现网站的流量负载。当然还可以为每一个web节点提供一个域名,这样加入其中一个域名被限制,那么另外几台web节点还是能通过其他域名正常访问。
而我们所说的域名镜像和网站镜像比较类似,上述案例中,将 www.test1.com 和 www.test2.cn 都能跳转到 www.test.com,那么 www.test.com 我们就可以把它起名叫主域名,其他两个就是我们所说的镜像域名,当然如果我们不想把整个网站做镜像,只想为其中某一个子目录下的资源做镜像,我们可以在location块中配置rewrite功能,比如:
# 比如,只想针对user功能模块做镜像,即访问www.test1.com 或 www.test2.cn 域名下的user资源时,不进行跳转,访问其他资源时跳转到www.test.com来
[root@nginx ~]# vim /etc/nginx/conf.d/hosts.conf
server {
listen 80;
server_name www.test.com;
location / {
default_type text/html;
return 200 '<h1>It is test!';
}
}
server {
listen 80;
server_name www.test1.com www.test2.cn;
#rewrite ^(.*) http://www.test.com$1;
location /user {
rewrite ^(/user)(.*)$ http://www.test1.com$1$2;
}
}
(三)独立域名
一个完整的项目包含多个模块,比如购物网站有商品搜索模块、商品详情模块和购物车模块等,如何为每一个模块设置独立的域名。
需求:
http://search.test.com:81 访问商品搜索模块
http://item.test.com:82 访问商品详情模块
http://cart.test.com:83 访问商品购物车模块
server{
listen 81;
server_name test.com;
rewrite ^(.*) http://www.test.com/search$1;
}
server{
listen 82;
server_name item.test.com;
rewrite ^(.*) http://www.test.com/item$1;
}
server{
listen 83;
server_name cart.test.com;
rewrite ^(.*) http://www.test.com/cart$1;
}
(四)合并目录
搜索引擎优化(SEO)是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内排名的方式。我们在创建自己的站点时,可以通过很多中方式来有效的提供搜索引擎优化的程度。其中有一项就包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,使用rewrite如何解决上述问题。
比如:
网站中有一个资源文件的访问路径时 /server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成 http://IP:PORT/server/11/22/33/44/20.html。
[root@nginx ~]# vim /etc/nginx/conf.d/test.conf
server {
listen 8082;
server_name localhost;
location /server {
root /myweb;
index index.html;
}
}
[root@nginx ~]# mkdir -p /myweb/server/11/22/33/44/
[root@nginx ~]# echo "<h1> server! </h1>" > /myweb/server/11/22/33/44/20.html
[root@nginx ~]# tree /myweb/server/
/myweb/server/
└── 11
└── 22
└── 33
└── 44
└── 20.html
4 directories, 1 file
[root@nginx ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# nginx -s reload
访问
但是这个时非常不利于SEO搜索引擎优化的,同时客户端也不好记。使用rewrite指令进行如下配置:
[root@nginx ~]# vim /etc/nginx/conf.d/test.conf
server {
listen 8082;
server_name localhost;
location /server {
root /myweb;
index index.html;
rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+).html$ /server/$1/$2/$3/$4/$5.html last;
}
}
[root@nginx ~]# nginx -s reload
访问