Nginx中的Rewrite的重定向配置与实践

简介:Rewrite是Nginx服务器提供的一个重要的功能,它可以实现URL重定向功能。
回到顶部

一:理解地址重写 与 地址转发的含义。

地址重写地址转发是两个不同的概念。

地址重写 是为了实现地址的标准化,比如我们可以在地址栏中中输入 www.baidu.com. 我们也可以输入 www.baidu.cn. 最后都会被重写到 www.baidu.com 上。浏览器的地址栏也会显示www.baidu.com。

地址转发:它是指在网络数据传输过程中数据分组到达路由器或桥接器后,该设备通过检查分组地址并将数据转发到最近的局域网的过程。

因此地址重写和地址转发有以下不同点:

  1. 地址重写会改变浏览器中的地址,使之变成重写成浏览器最新的地址。而地址转发他是不会改变浏览器的地址的。
  2. 地址重写会产生两次请求,而地址转发只会有一次请求。
  3. 地址转发一般发生在同一站点项目内部,而地址重写且不受限制。
  4. 地址转发的速度比地址重定向快。
    回到顶部

二:理解 Rewrite指令 使用

该指令是通过正则表达式的使用来改变URI。可以同时存在一个或多个指令。需要按照顺序依次对URL进行匹配和处理。

该指令可以在server块或location块中配置,其基本语法结构如下:

rewrite regex replacement [flag];

rewrite的含义:该指令是实现URL重写的指令。
regex的含义:用于匹配URI的正则表达式。
replacement:将regex正则匹配到的内容替换成 replacement。
flag: flag标记。

flag有如下值:

last: 本条规则匹配完成后,继续向下匹配新的location URI 规则。(不常用)
break: 本条规则匹配完成即终止,不再匹配后面的任何规则(不常用)。
redirect: 返回302临时重定向,浏览器地址会显示跳转新的URL地址。
permanent: 返回301永久重定向。浏览器地址会显示跳转新的URL地址。

比如如下列子:

rewrite ^/(.*) http://www.baidu.com/$1 permanent;

说明:
rewrite 为固定关键字,表示开始进行rewrite匹配规则。
regex 为 ^/(.)。 这是一个正则表达式,匹配完整的域名和后面的路径地址。
replacement就是 http://www.baidu.com/$1 这块了,其中$1是取regex部分()里面的内容。如果匹配成功后跳转到的URL。
flag* 就是 permanent,代表永久重定向的含义,即跳转到 http://www.baidu.com/$1 地址上。

下面我们来做个简单的demo来模拟下:

  1. 在我们的测试项目下有个app.js. 代码如下:
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
// 添加路由
router.get('/', ctx => {
ctx.body = '欢迎光临index page 页面';
});
router.get('/home', ctx => {
ctx.body = '欢迎光临home页面';
});
router.get('/404', ctx => {
ctx.body = '404...'
});
// 加载路由中间件
app.use(router.routes());
app.listen(3001, () => {
console.log('server is running at http://localhost:3001');
});

然后在命令行中 运行 node app.js 后,运行,我们就可以在浏览器中 访问 http://localhost:3001 就可以访问到我们对应的页面了。但是现在我想把该node项目
部署到我本地的nginx服务器上。nginx安装请看我这篇文章 然后我想使用域名来访问我们的项目,因此我们需要在我们的nginx.conf中配置一下:

cd /usr/local/etc/nginx

然后使用命令:sudo open /usr/local/etc/nginx/nginx.conf -a ‘sublime text’ 命令打开 nginx.conf 配置如下:

#keepalive_timeout

root html;
}
}
server {
listen 8088 ;
server_name xxx.abc.com;
location / {
proxy_pass http://127.0.0.1:3001;
rewrite ^/(.*) http://www.baidu.com permanent;
}
}
}

如上代码,我监听端口号是8088,然后server_name 配置设置为 xxx.abc.com, 然后当我们访问 http://xxx.abc.com:8088/的时候,会先反向代理到我们的http://127.0.0.1:3001下的node对应的页面上来,反向代理完成后,会使用 rewrite 重定向百度页面去了。如上配置完成后,我们需要重启下nginx服务器;使用命令:

Nginx中的Rewrite的重定向配置与实践

然后当我们在浏览器访问 http://xxx.abc.com:8088/ 的时候,会执行如下图所示,它会先对 http://xxx.abc.com:8088/ 进行永久重定向(301), 然后会访问百度(307),临时重定向到百度页面来,最终加载百度页面的地址;如下演示所示:

Nginx中的Rewrite的重定向配置与实践

Nginx中的Rewrite的重定向配置与实践

Nginx中的Rewrite的重定向配置与实践

但是如果我把 permanent 改成 redirect 的话,比如nginx配置:rewrite ^/(.*) http://www.baidu.com redirect; 后,它就会变成302临时重定向了。如下所示:

Nginx中的Rewrite的重定向配置与实践
回到顶部

三:理解if指令

该指令用来支持条件判断的,并且根据条件判断结果来选择不同的nginx的配置,我们可以在server块或location块中配置该指令,它的语法结构为:

if (condition) {
  // ....

}

condition 是布尔值 true/false的含义。

Rewrite 指令可用的全局变量如下:

  1. $args: 该变量中存放了请求URL中的请求指令。比如 http://127.0.0.1:3001?arg1=value1&arg2=value2 中的
    “arg1=value1&arg2=value2″。
  2. $content_length: 该变量中存放了请求头中的Content-length字段。
  3. $content_type: 该变量中存放了请求头中的 Content-type字段。
  4. $document_root: 该变量中存放了针对当前请求的根路径。
  5. $document_uri: 该变量中存放了请求的当前URI, 但是不包括请求指令。比如 http://xxx.abc.com/home/1?arg1=value1&
    arg2=value2; 中的 “/home/1”
  6. $host: 变量中存放了请求的URL中的主机部分字段,比如http://xxx.abc.com:8080/home中的 xxx.abc.com.

  7. $http_host: 该变量与$host唯一区别带有端口号:比如上面的是 xxx.abc.com:8080

  8. $http_user_agent: 变量中存放客户端的代理信息。
  9. $http_cookie, 该变量中存放客户端的cookie信息。
  10. $remote_addr 该变量中存放客户端的地址。
  11. $remote_port 该变量中存放了客户端与服务器建立连接的端口号。
  12. $remote_user 变量中存放客户端的用户名。
  13. $request_body_file 变量中存放了发给后端服务器的本地文件资源的名称
  14. $request_method 变量中存放了客户端的请求方式,比如 ‘GET’、’POST’等。
  15. $request_filename 变量中存放了当前请求的资源文件的路径名。
  16. $request_uri 变量中存放了当前请求的URI,并且带请求指令。
  17. $query_string 和变量$args含义一样。
  18. $scheme 变量中存放了客户端请求使用的协议,比如 ‘http’, ‘https’等。
  19. $server_protocol 变量中存放了客户端请求协议的版本, 比如 ‘HTTP/1.0’、’HTTP/1.1’ 等。
    ….. 等等

正则表达式的基本语法:

  1. 对变量进行匹配

‘~’ 表示匹配过程中对大小写敏感。
‘~‘ 表示匹配过程中对大小写不敏感。
‘!~’ 如果 ‘~’ 匹配失败时,那么该条件就为true。
‘!~
‘ 如果 ‘~*’ 匹配失败时,那么该条件就为true。

比如如下:

if ($http_user_agent ~ MSIE) {
  // 代码的含义:$http_user_agent值中是否含有 MSIE 字符串,如果包含为true,否则为false
}
  1. 判断请求的文件是否存在

‘-f’ 如果请求的文件存在,那么该条件为true。
‘!-f’ 如果该文件的目录存在,该文件不存在,那么返回true。如果该文件和目录都不存在,则为false。
如果请求的目录不存在,请求的文件存在,也为false。

if (-f $request_filename) {
  // 判断请求的文件是否存在
}
if (!-f $request_filename) {
// 判断请求的文件是否不存在
}
  1. 判断请求的目录是否存在使用 ‘-d’ 和 ‘!-d’

使用 ‘-d’,如果请求的目录存在,则返回true。否则返回false。
使用 ‘!-d’, 如果请求的目录不存在,但是该请求的上级目录存在,则返回true。如果该上级目录不存在,则返回false…. 等等其他一些语法,不多介绍。

现在我们使用if指令来对nginx加一些判断;比如说我们访问http://xxx.abc.com:8080/home时候,如果$host = ‘xxx.abc.com’ 的时候,就做重定向跳转,nginx配置代码如下:

server {
  listen 8088;
  server_name xxx.abc.com;
  location / {
    proxy_pass http://127.0.0.1:3001;
    if ($host = 'xxx.abc.com') {
      rewrite ^/(.*) http://www.cnblogs.com redirect;
    }
  }
}

nginx 如上配置,如果我们访问 http://xxx.abc.com:8088 的时候,它就会重定向到 http://www.cnblogs.com 来了。

Nginx中的Rewrite的重定向配置与实践

比如更多的判断,比如如果用户代理是手机访问的话,直接跳转到某个页面去,也可以使用if判断。比如如下:

if ( $http_user_agent ~* "(Android)|(iPhone)|(Mobile)|(WAP)|(UCWEB)" ){
  rewrite ^/$  http://www.cnblogs.com  permanent;
}

回到顶部

四:理解防盗链及nginx配置

什么是防盗链?盗链可以理解盗图链接,也就是说把别人的图片偷过来用在自己的服务器上,那么防盗链可以理解为防止其他人把我的图片盗取过去。

防盗链的实现原理:客户端向服务器端请求资源时,为了减少网络带宽,提高响应时间,服务器一般不会一次将所有资源完整地传回客户端。比如请求一个网页时,首先会传回该网页的文本内容,当客户端浏览器在解析文本的过程中发现有图片存在时,会再次向服务器发起对该图片资源的请求,服务器将存储的图片资源再发送给客户端。但是如果这个图片是链接到其他站点的服务器上去了呢,比如在我项目中,我引用了的是淘宝中的一张图片的话,那么当我们网站重新加载的时候,就会请求淘宝的服务器,那么这就很有可能造成淘宝服务器负担。因此这个就是盗链行为。因此我们要实现防盗链。

实现防盗链:使用http协议中请求头部的Referer头域来判断当前访问的网页或文件的源地址。通过该头域的值,我们可以检测访问目标资源的源地址。如果目标源地址不是我们自己站内的URL的话,那么这种情况下,我们采取阻止措施,实现防盗链。但是注意的是:Referer头域中的值是可以被更改的。因此该方法也不能完全安全阻止防盗链。

使用Nginx服务器的Rewrite功能实现防盗链。

Nginx中有一个指令 valid_referers. 该指令可以用来获取 Referer 头域中的值,并且根据该值的情况给 Nginx全局变量 $invalid_referer 赋值。如果Referer头域中没有符合 valid_referers指令的值的话,$invalid_referer变量将会赋值为1. valid_referers 指令基本语法如下:

valid_referers  none | blocked | server_names | string

none: 检测Referer头域不存在的情况。
blocked: 检测Referer头域的值被防火墙或者代理服务器删除或伪装的情况。那么在这种情况下,该头域的值不以”http://” 或 “https://” 开头。

server_names: 设置一个或多个URL,检测Referer头域的值是否是URL中的某个。

因此我们有了 valid_referers指令和$invalid_referer变量的话,我们就可以通过 Rewrite功能来实现防盗链。
下面我们介绍两种方案:第一:根据请求资源的类型。第二:根据请求目录。

  1. 根据请求文件类型实现防盗链配置实列如下:
server {
  listen 8080;
  server_name xxx.abc.com
  location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ {
    valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com  *.tabobao.com;
    if ($invalid_referer) {
      rewrite ^/ http://www.xxx.com/images/forbidden.png;
    }
  }
}

如上基本配置,当有网络连接对以 gif、jpg、png为后缀的图片资源时候、当有以swf、flv为后缀的媒体资源时、或以 rar、zip为后缀的压缩资源发起请求时,如果检测到Referer头域中没有符合 valid_referers指令的话,那么说明不是本站的资源请求。

location ~* ^.+.(gif|jpg|png|swf|flv|rar|zip)$ 该配置的含义是 设置防盗链的文件类型。

valid_referers none blocked www.xxx.com www.yyy.com .baidu.com .tabobao.com; 可以理解为白名单,允许文件链出的域名白名单,如果请求的资源文件不是以这些域名开头的话,就说明请求的资源文件不是该域下的请求,因此可以判断它是盗链。因此如果不是该域下的请求,就会使用 Rewrite进行重定向到 http://www.xxx.com/images/forbidden.png 这个图片,比如这张图片是一个x或其他的标识,然后其他的网站就访问不了你这个图片哦。

  1. 根据请求目录实现防盗链的配置实列如下:
server {
  listen 8080;
  server_name xxx.abc.com
  location /file/ {
    root /server/file/;
    valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com  *.tabobao.com;
    if ($invalid_referer) {
      rewrite ^/ http://www.xxx.com/images/forbidden.png;
    }
  }
}

Original: https://www.cnblogs.com/faberbeta/p/16410604.html
Author: 快乐嘉年华
Title: Nginx中的Rewrite的重定向配置与实践

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/543787/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • spring mvc通过客户端传值,controller获取Sort对象

    之前客户端需要根据需求按不同的排序方式查看数据,按照一种约定排序,比如1代表时间升序,2代表时间降序,3,4这种形式,然后后台根据这些值创建Sort对象。 后来发现完全多此一举,可…

    Java 2023年6月7日
    075
  • 半同步半异步线程池框架代码实现

    cpp;gutter:true; SyncTaskQueue.h</p> <h1>pragma once</h1> <h1>incl…

    Java 2023年5月30日
    071
  • Spring Security配置多个数据源并添加登录验证码(7)

    1.配置多个数据源 多个数据源是指在同一个系统中,用户数据来自不同的表,在认证时,如果第一张表没有查找到用户,那就去第二张表中査询,依次类推。 看了前面的分析,要实现这个需求就很容…

    Java 2023年6月13日
    067
  • Mac下多版本JDK安装

    1.下载 &#x94FE;&#x63A5;: <span class="hljs-symbol">http:/<span cl…

    Java 2023年5月30日
    067
  • 中国DevOps平台市场,华为云再次位居领导者位置

    摘要:华为云软件开发生产线DevCloud在市场份额和发展战略两大维度均排名第一,再次位居领导者位置。 9月21日 ,国际权威分析师机构IDC发布《IDC MarketScape:…

    Java 2023年6月15日
    061
  • [spring]spring和mybatis的整合与事务处理

    1.导包 junit junit 4.13.1 mysql mysql-connector-java 8.0.29 org.mybatis mybatis 3.5.3 org.sp…

    Java 2023年6月6日
    088
  • 马士兵多线程直播笔记(下)

    马士兵多线程直播笔记(下) CPU与缓存 缓存L1、L2、L3失效后回去内存中找,然后依次返回L3、L2、L1. 缓存一致性协议(MESI) 同一个缓存行在多个CPU内存中,一个修…

    Java 2023年5月30日
    059
  • Spring RestTemplate用法

    RestTemplate简介 RestTemplate对HTTP请求进行了封装,进行请求的时候可以保留cookie,在下次请求的时候使用; postForEntity与postFo…

    Java 2023年5月30日
    072
  • SpringBoot-druid

    SpringBoot-druid 9.1 druid简介 Java程序很大一部分要操作数据库,为了提高性能操作数据库,又不得不使用数据库连接池。 Druid 是阿里巴巴开源平台上一…

    Java 2023年6月5日
    065
  • Bigdecimal的格式化以及长度判断

    Bigdecimal的格式化 需求 Bigdecimal的长度太长 需要处理 1.定义一种格式 decimalFormat.setRoundingMode (RoundingMod…

    Java 2023年6月9日
    067
  • Websocket实现前后台通信,demo小测试

    新需求大概如下:用户登录系统,登录成功之后建立websocket连接,实现通信 总体思路:前端不是我负责,只是简单的做个功能,先实现登录,把用户标识存入HttpSeesion,再建…

    Java 2023年6月8日
    075
  • Java清屏函数

    Java清屏函数 Java清屏函数 前因 代码 前因 因为最近在做Java课程的大作业,一个基于控制台交互的程序,试图绘制界面,希望每次对console清屏,在网上找了很多清屏函数…

    Java 2023年6月5日
    073
  • 【源码】按照自己的思路研究Spring AOP源码 ①

    一个例子 从@EnableAspectJAutoProxy注解入手 什么时候会创建代理对象? 方法执行时怎么实现拦截的? 总结 问题 参考 一个例子 // 定义一个切面 packa…

    Java 2023年6月8日
    085
  • 力扣Q239滑动窗口最大值SlidingWindowMaximum

    Q239SlidingWindowMaximum 简介 给你一个整数数组 nums ,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k …

    Java 2023年6月8日
    081
  • JAVA自已设计JSON解析器

    当然,有很多很好的JSON解析的JAR包,比如JSONOBJECT,GSON,甚至也有为我们测试人员而打造的JSONPATH,但我还是自已实现了一下(之前也实现过,现在属于重构)。…

    Java 2023年5月29日
    045
  • 琐碎的想法(二)网络协议——人们给计算机的一组“约定”

    网络协议学习方式一 学习网络协议的入门多种多样,如果是从术语上来讲协议,大概是这样的。 这是一种靠强记,通过实践来加深印象,最后不自知地了解网络协议的过程。有效但趣味寥寥。 网络协…

    Java 2023年6月8日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球