一、什么是 URL 重写?
URL重写是指将一个URL请求重新写成网站可以处理的另一个URL的过程。 而为什么要修改URL呢?是为了安全,以及提高用户的体验。
- URL Rewrite最常见的应用是URL伪静态化,是将动态页面显示为静态页面方式的一种技术。比如http://www.123.com/news/index.php?id=123 使用URLRewrite 转换后可以显示为 http://www.123.com/news/123.html
- 从安全角度上讲,如果在URL中暴露太多的参数,无疑会造成一定量的信息泄漏,可能会被一些黑客利用,对你的系统造成一定的破坏,所以静态化的URL地址可以给我们带来更高的安全性。
- 实现网站地址跳转,例如用户访问360buy.com,将其跳转到jd.com。例如当用户访问tianyun.com的
80端口时,将其跳转到443端口。
二、重定向应用场景
- 地址跳转:用户访问www.123.com这个URL是,将其定向至一个新的域名test.456.com
- 协议跳转:用户通过http协议请求网站时,将其重新跳转至https协议方式,即80转443。
- 伪静态:将动态页面显示为静态页面方式的一种技术, 伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。
- 搜索引擎:SEO优化依赖于url路径, 通过对URL的一些优化,可以使搜索引擎更好的识别与收录网站的信息 。
三、重定向指令
Nginx Rewrite相关指令有 if、rewrite、set、return
3.1 if 指令
应用环境:server,location
(1)语法
if (condition) { … }
if 可以支持如下条件判断匹配符号。
~ 正则匹配 (区分大小写)
~* 正则匹配 (不区分大小写)
!~ 正则不匹配 (区分大小写)
!~* 正则不匹配 (不区分大小写)
-f 和!-f 用来判断是否存在文件
-d 和!-d 用来判断是否存在目录
-e 和!-e 用来判断是否存在文件或目录
-x 和!-x 用来判断文件是否可执行
(2)Nginx的全局变量(可引用)
$args 请求中的参数;
$document_root 针对当前请求的根路径设置值;
$host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;
$limit_rate 对连接速率的限制;
$request_method 请求的方法,比如"GET"、"POST"等;
$remote_addr 客户端地址;
$remote_port 客户端端口号;
$remote_user 客户端用户名,认证用;
$request_filename 当前请求的文件路径名(带网站的主目录/usr/local/nginx/html/images/a.jpg)
$request_uri 当前请求的文件路径名(不带网站的主目录/images/a.jpg)
$query_string 与$args相同;
$scheme 用的协议,比如http或者是https;
$server_protocol 请求的协议版本,"HTTP/1.0"或"HTTP/1.1";
$server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费);
$server_name 请求到达的服务器名;
$document_uri 与$uri一样,URI地址;
$server_port 请求到达的服务器端口号;
(3)Rewrite flag
rewrite 指令根据表达式来重定向URI,或者修改字符串。可以应用于server,location, if环境下每行rewrite指令最后跟一个flag标记,支持的flag标记有:
标记 | 作用 |
---|---|
last | 相当于Apache里的[L]标记,表示完成rewrite,默认为last。 |
break | 本条规则匹配完成后,终止匹配,不再匹配后面的规则。 |
redirect | 返回302临时重定向,浏览器地址会显示跳转后的URL地址。 |
permanent | 返回301永久重定向,浏览器地址会显示跳转后URL地址。 |
permanent和redirect区别:
-
permanent
对于客户端来说一般状态下是没有区别的。而对于搜索引擎,相对来说301的重定向更加友好,如果我们把一个地址采用301跳转方式跳转的话,搜索引擎会把老地址的相关信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。 -
redirect
使用302重定向时,搜索引擎(特别是google)有时会查看跳转前后哪个网址更直观,然后决定显示哪个,如果它觉的跳转前的URL更好的话,也许地址栏不会更改。
3.2 rewrite 指令
(1)语法
rewrite regex replacement [flag];
重写 正则匹配 替换目标 标记(可选)
(2)示例
【示例1】
http://192.168.0.101/a/a.html ==> http://192.168.0.101/b/URL.gif
server {
listen 80;
server_name localhost;
location /a {
root /var/www/nginx;
index a.html index.htm;
rewrite .* /b/URL.gif permanent;
}
location /b {
root /var/www/nginx; #上传图片 URL.gif 到/var/www/nginx/b下
}
}
-
输入URL
-
输入URL后回车
【示例2】
http://192.168.0.101/2019/a/a.html ==> http://192.168.0.101/2020/a/a.html
server {
listen 80;
server_name localhost;
location /2019/a {
root /var/www/nginx;
index a.html index.htm;
rewrite ^/2019/(.*)$ /2020/$1 permanent; #这里的$1表示取出第一个()里的值,即 a
}
location /2020/a {
root /var/www/nginx; #上传图片 URL.gif 到/var/www/nginx/b下
}
}
-
输入URL
-
输入URL后回车
【示例3】
http://www.zrsit.com/a/a.html ==> http://baidu.com/
server {
listen 80;
server_name localhost;
location /a {
root /var/www/nginx;
index a.html index.htm;
if ($host ~* www.zrsit.com) {
rewrite .* http://www.baidu.com permanent; #重写到baidu.com
}
}
}
-
输入URL
-
输入URL后回车
【示例4】
http://www.zrsit.com/a/a.html ==> http://baidu.com/a/a.html
server {
listen 80;
server_name localhost;
location /a {
root /var/www/nginx;
index a.html index.htm;
if ($host ~* www.zrsit.com) {
rewrite .* http://www.baidu.com$request_uri permanent; #重写到baidu.com/a/a.html。这里$request_uri为内置变量,取的是你访问域名 qf.com 的二级目录/a/1.html 的内容
}
}
}
-
输入URL
-
输入URL后回车
【示例5】
http://www.zrsit.com/login/a.html ==> http://www.zrsit.com/reg/a.html?user=a
server {
listen 80;
server_name localhost;
location /login {
root /var/www/nginx;
index a.html index.htm;
rewrite ^/login/(.*)\.html$ http://$host/reg/a.html?user=$1; #$1为前面括号内容
}
location /reg {
root /var/www/nginx;
index a.html index.htm;
}
}
-
输入URL
-
输入URL后回车
3.3 set 指令
set 指令是用于定义一个变量,并且赋值。
应用环境:server、location、if
http://alice.test.com ==> http://www.test.com/tom
http://jack.test.com ==> http://www.test.com/jack
(1)本地域名解析
10.20.151.8 www.test.com
10.20.151.8 tom.test.com
10.20.151.8 jack.test.com
(2)编辑Nginx配置文件
[root@server-yum1 jack]# vim /etc/nginx/conf.d/test.conf
server {
listen 80;
server_name www.test.com;
location / {
root /var/www/nginx;
index index.html index.htm;
if ( $host ~* ^www.test.com$) {
break; #当匹配到www.test.com时终止匹配
}
if ( $host ~* "^(.*)\.test\.com$" ) {
set $user $1;
rewrite .* http://www.test.com/$user permanent; #当匹配到jack.test.com时,交给 “location /jack” 处理,匹配到tom.test.com时,交给 “location /tom” 处理。
}
}
location /jack {
root /var/www/nginx;
index jack.html index.hml;
}
location /tom {
root /var/www/nginx;
index tom.html index.hml;
}
}
(3)添加测试数据
[root@nginx-server conf.d]# cd /var/www/nginx/
[root@nginx-server html]# mkdir jack tom
[root@nginx-server html]# echo "hello jack" >> jack/jack.html
[root@nginx-server html]# echo "hello tom" >> tom/tom.html
(4)浏览器端测试
3.4 return 指令
return 指令用于返回状态码给客户端。
应用环境:server、location、if
如果访问的.sh结尾的文件则返回403操作拒绝错误。
(1)Nginx配置
server {
listen 80;
server_name www.testpm.cn;
location / {
root /var/www/nginx;
index index.html index.htm;
}
location ~* \.sh$ {
return 403;
}
}
(2)创建测试数据
[root@server-yum1 nginx]# cat index.html
This is a test !!
(3)浏览器端访问www.test.com
当我访问以.sh结尾的文件www.test.com/123.sh时,会返回403状态码。
四、last 和 break 的区别
在3.1小节中已经提到了Rewrite flag,下面来看一下last、break的用法。
(1)Nginx配置
这里我使用的域名是www.test.com(我在上面已经进行过本地解析)
server {
listen 80;
server_name localhost;
location / {
root /var/www/nginx;
index index.html index.htm;
}
location /break/ { #当我匹配到www.test.com/break/时,给我重写到www.test.com/test/break.html 因其后标记为break,故匹配完后终止匹配。
root /var/www/nginx;
rewrite .* /test/break.html break;
}
location /last/ { #当我匹配到www.test.com/last/时,给我重写到www.test.com/test/last.html,因其后标记为last,故重新对server { … } 标签重新发起请求,这时就会匹配到www.test.com/test/test.html,匹配到这里时又因为其后有break,故匹配完后终止匹配。
root /var/www/nginx;
rewrite .* /test/last.html last;
}
location /test/ {
root /var/www/nginx;
rewrite .* /test/test.html break;
}
}
(2)创建测试数据
[root@server-yum1 nginx]# pwd
/var/www/nginx
[root@server-yum1 nginx]# echo "last" > test/last.html
[root@server-yum1 nginx]# echo "break" > test/break.html
[root@server-yum1 nginx]# echo "test" > test/test.html
(3)浏览器端测试
-
地址栏输入www.test.com时:
-
地址栏输入www.test.com/break/时:
-
地址栏输入www.test.com/last/时:
last和break的区别:
- last 标记在本条 rewrite 规则执行完后,会对其所在的 server { … } 标签重新发起请求;
- break 标记则在本条规则匹配完成后,停止匹配,不再做后续的匹配;
- 使用 proxy_pass 指令时,则必须使用break。