一、Rewrite基本介绍
1.1 什么是Rewrite
Rewrite主要实现url地址重写, 以及url地址跳转。就是将用户请求web服务器的URL地址重新修改为其他URL地址的过程。
比如说京东,google、亚马逊都在使用
域名 | 重写后域名 |
---|---|
www.z.cn | www.amazon.cn |
www.g.cn | www.google.cn |
www.360buy.com | www.jd.com |
58.com | bj.58.com |
1.2 Rewrite应用场景
- 地址跳转,用户访问www.jd.com这个URL时,将其定向至一个新的域名m.jd.com
- 协议跳转,将用户通过http的请求协议重新跳转至https协议(实现https主要手段)。
- URL静态化,将动态URL地址显示为静态URL的一种技术,能提高搜索引擎抓取,并且能减少动态URL对外暴露过多的参数。
1.3 Rewrite重写原理
1.4 Rewrite重写模块
- set 设置变量
- if 语句判断
- return 返回返回值或URL
- rewrite 重定向URL
二、Rewrite重写模块
2.1 if条件判断指令
语法:
Syntax: if (condition) { ... }
Default: —
Context: server, location
# ~ 模糊匹配
# ~* 不区分大小写的匹配
# !~ 不匹配
# = 精确匹配
示例:
需求:匹配Nginx请求中包含id=1234的,然后代理到 10.16.3.5 的8080端口
[root@web01 conf.d]# cat url1.conf
server {
listen 80;
server_name url1.bertwu.net;
root /code;
location / {
index index.html;
if ( $request_uri ~* 'id=\d{4}' ) {
proxy_pass http://10.16.3.5:8080;
}
}
}
2.2 set设定变量指令
语法:
Syntax: set $variable value;
Default: —
Context: server, location, if
示例:
# 需求:通过user_agent(Header)拦截压测测试工具、程序爬虫等
# user_agent:
# chrome ,firefox, curl/7.29.0
# 1.确认来请求的用户是使用的curl命令,如果是则做一个标记,设置为1;
# 2.判断标记,如果标记的值假设为1,我们就拒绝,如果不为1则不处理;
[root@web01 conf.d]# cat set.conf
server {
listen 80;
server_name set.bertwu.net;
root /code;
location / {
index index.html;
if ( $http_user_agent ~* 'curl|python|wget|apachbench' ) {
set $flag 1;
}
if ( $flag = 1 ) {
return 403;
}
}
}
访问,被禁止
root@web02 ~]# curl -H Host:set.bertwu.net http://10.0.0.7:80
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>
2.3 return返回数据指令
语法:
Syntax:
return code;
return code [text];
return URL;
Default: —
Context: server, location, if
示例
需求:客户端使用IE或火狐浏览器访问站点,则返回段字符串或返回错误或重定向
server {
listen 80;
server_name ret.bertwu.net;
root /code;
charset utf-8;
location / {
index index.html;
default_type text/html;
if ( $http_user_agent ~* "MSIE|firefox|trident" ) {
#return 500; # 返回状态码
return 200 "Change Brower..."; # 返回状态码+text
#return 302 https://www.baidu.com; # 返回 code + url
}
}
}
三、Rewrite重写Flag
rewrite主要是用来重写URL或者跳转URL的指令。
#rewrite表达式可以应用在server,location, if标签下
# 关键字 正则 替代内容 flag标记
Syntax: rewrite regex replacement [flag];
Default: --
Context: server, location, if
#flag
last #本条规则匹配完成后,继续向下匹配新的location URI规则
break #本条规则匹配完成即终止,不再匹配后面的任何规则
redirect #返回302临时重定向, 地址栏会显示跳转后的地址
permanent #返回301永久重定向, 地址栏会显示跳转后的地址
3.1 测试准备
[root@web01 conf.d]# cat rewrite.conf
server {
listen 80;
server_name rew.bertwu.net;
root /code/code1;
location / {
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
[root@web01 conf.d]# echo "1.html" >/code/code1/1.html
[root@web01 conf.d]# echo "2.html" >/code/code1/2.html
[root@web01 conf.d]# echo "3.html" >/code/code1/3.html
[root@web01 conf.d]# echo "a.html" >/code/code1/a.html
[root@web01 conf.d]# echo "b.html" >/code/code1/b.html
#结果:当请求/1.html,最终将会访问/b.html
3.2 Break与last
3.2.1 Break
在location{}内部,遇到break,本location{}内以及后面的所有location{}内的所有指令都不再执行
[root@web01 conf.d]# cat rewrite.conf
server {
listen 80;
server_name rew.bertwu.net;
root /code/code1;
location / {
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
测试结果: 当请求/1.html,最终会访问/2.html
3.2.2 last
在location{}内部,遇到last,本location{}内后续指令不再执行,而重写后的url会对所在的server{…}标签重新发起请求,从头到尾匹配一遍规则,哪个匹配则执行哪个。
[root@web01 conf.d]# cat rewrite.conf
server {
listen 80;
server_name rew.bertwu.net;
root /code/code1;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
测试结果:当请求/1.html,最终会访问/a.html
3.2.3 break与last区别
- 当rewrite规则遇到break后,本location{}与其他location{}的所有规则都不执行。
- 当rewrite规则遇到last后,本location{}里后续规则不执行,但重写后的url会再次从头开始匹配所有Location,哪个匹配执行哪个。
3.3 redirect与permanent
3.3.1 为代码添加redirect
[root@web01 conf.d]# cat rewrite.conf
server {
listen 80;
server_name rew.bertwu.net;
root /code/code1;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
3.3.2 为代码添加permanent
[root@web01 conf.d]# cat rewrite.conf
server {
listen 80;
server_name rew.bertwu.net;
root /code/code1;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
3.3.3 redirect与permanent区别
- redirect临时跳转302,对旧网站无影响,新网站会有排名(不会缓存)
- permanent永久跳转301,对新跳转网站有排名,旧网站排名会被清空(缓存下来)
四、Rewrite 生产案例实践
- 需求:根据用户浏览器请求头中携带的语言调度到不同的页面
[root@web01 conf.d]# cat language.conf
server {
listen 80;
server_name lan.bertwu.net;
root /code/code1;
if ( $http_accept_language ~* 'zh-CN|zh' ) {
set $language zh;
}
if ( $http_accept_language ~* 'en' ) {
set $language en;
}
rewrite ^/$ /$language;
location / {
index index.html;
}
}
- 需求:用户通过手机设备访问 agent.bertwu.net,跳转至agent.bertwu.net/m
[root@web01 conf.d]# cat agent.conf
server {
listen 80;
server_name agent.bertwu.net;
root /code;
if ($http_user_agent ~* 'iphon|android|ipad') {
rewrite ^/$ /m;
}
location / {
index index.html;
}
}
[root@web01 conf.d]# echo 'chrom---' > /code/index.html
[root@web01 conf.d]# mkdir /code/m;
[root@web01 conf.d]# echo 'android---' > /code/m/index.html
3. 用户通过手机设备访问 url.bertwu.net跳转至 m.bertwu.net
[root@web01 conf.d]# cat m.bertwu.conf
server {
listen 80;
server_name url.bertwu.net;
root /code;
if ( $http_user_agent ~* 'android|iphone|ipad' ) {
rewrite ^/$ http://m.url.bertwu.net redirect;
}
location / {
index index.html;
}
}
server {
listen 80;
server_name m.url.bertwu.net;
root /code/m;
location / {
index index.html;
}
}
- 需求:用户通过http协议请求,能自动跳转至https协议。
server {
listen 80;
server_name url.bertwu.net;
root /code1;
# $http_host
# $server_name
# $host 这三种方式一样
return 302 https://$http_host$request_uri;
#rewrite ^(.*)$ https://$http_host$1 redirect;
}
server {
listen 443;
server_name url.bertwu.net;
location / {
}
}
5.网站维护过程中,希望所有用户请求重新跳转到一个页面
server {
listen 80;
server_name url.bertwu.net;
root /code;
# 直接写在server层,防止过多的location重复写,维护页面的开关
# rewrite ^(.*)$ /wh.html break;
location / {
index index.html;
}
6.需求:当服务器遇到403404 502等错误时,自动转到临时维护的静态页。
server {
listen 80;
server_name url.bertwu.net;
root /code;
location / {
index index.html;
}
error_page 404 403 502 @errorpage
location @errorpage {
rewrite ^(.*)& /wh.html break
}
7.对部分ip放行,对其他ip进入停机维护
server {
listen 80;
server_name url.bertwu.net;
root /code1;
# 设定ip变量为0
set $ip 0;
# 判断,如果来源的IP为节点的IP则设定ip变量为1,如果前面有七层负载均衡,建议使用 $http_x_forwarded_for
if ($remote_addr ~ "10.0.0.1|10.0.0.2") {
set $ip 1;
}
# 判断 如果ip变量为0 ,则进入维护页面;
if ($ip = 0) {
rewrite ^(.*)$ /wh.html break;
}
location / {
index index.html;
}
}
# 如果只需要对特定的location做限制,把上面写在特定location中即可
8.公司后台/admin 只允许公司出口IP可以访问,其他全部返回500或跳转首页
location /admin {
limit_rate 100k;
set $ip 0;
if ($remote_addr ~ "10.0.0.51") {
set $ip 1;
}
if ($ip = 0) {
#return 404;
#return 302 http://$http_host;
}
}
server {
listen 80;
server_name url.bertwu.net;
root /code1;
location / {
index index.html;
if ($http_host ~* (.*)\.(.*)\.(.*) ) {
set $domain $1;
}
rewrite ^(.*)$ http://demo:27610/$domain$request_uri redirect;
}
}
五、防盗链配置
防盗链,指的是防止资源被其他网站恶意盗用。如何避免网站资源被盗用:可以根据客户端请求所携带的Referer信息来验证请求的合法性,因为Referer会告诉服务器它是从哪一个域名点击过来的。
基于Referer限制盗链:
优点:规则简单、配置和使用都很方便,
缺点:防盗链所依赖的Referer验证信息是可以伪造的,并非100%可靠;但基于Referer限制盗链的方式,可以限制绝大多数盗链情况。
环境:
角色 | IP | 域名 |
---|---|---|
盗链节点(偷取资源) | 10.0.0.7 | sb.laowang.net |
被盗链节点(提供资源) | 10.0.0.8 | img.bertwu.net |
1.配置被盗链节点
[root@web02 conf.d]# cat img.bertu.conf
server {
listen 80;
server_name img.bertwu.net;
root /code;
location / {
index index.html;
}
}
然后往根目录下放置一张照片
2.配置盗链节点
[root@web01 conf.d]# cat www.bertwu.conf
server {
listen 80;
server_name sb.laowang.net;
root /code;
location / {
index index.html;
}
}
# index.html内容
[root@web01 conf.d]# cat /code/index.html
<html>
<head>
<meta charset="utf-8">
<title>bertwu.net</title>
</head>
<img src="http://img.bertwu.net/xld.jpg"/>
</html>
3.访问sb.laowang.ne,可以直接盗取图片
防盗语法:
# 基于http_referer防止资源被盗用
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
#none: Referer来源头部为空的情况(通常是浏览器直接访问)
#blocked: Referer来源头部不为空,直接填写允许的域名即可
#server_names: 来源头部包含当前的域名,可以正则匹配
4.防盗配置:
配置所有来自*.bertwu.com
都可以访问到img.bertwu.net
站点的图片。如果来源域名不在这个列表中,那么$invalid_referer变量值为1,后续通过if判断,进行错误返回;
[root@web02 conf.d]# cat img.bertu.conf
server {
listen 80;
server_name img.bertwu.net;
root /code;
location / {
index index.html;
}
location ~ .*\.(jpg|jpeg|gif|png)$ {
valid_referers none blocked *.bertwu.net; # 如果走我这里 invalid_referer为0 否则非零
if ($invalid_referer) {
return 403;
}
}
}
再次访问,发现已经失败。
# 允许 google、baidu、等站点能够(盗链)资源,那么则可以通过server_names开放
# location ~* \.(gif|jpg|png|bmp)$ {
valid_referers none blocked *.bertwu.net server_names ~\.google\. ~\.baidu\.;
如果检测到被盗,也可以返回一张恶搞图片
[root@web02 conf.d]# cat img.bertu.conf
server {
listen 80;
server_name img.bertwu.net;
root /code;
location / {
index index.html;
}
location ~ .*\.(jpg|jpeg|gif|png)$ {
valid_referers none blocked *.bertwu.net;
if ($invalid_referer) {
rewrite ^(.*)$ /error.jpg break;
}
}
}