前端开发掌握nginx常用功能之rewrite

上一篇博文对nginx最常用功能的server及location的匹配规则进行了讲解,这也是nginx实现控制访问和反向代理的基础。掌握请求的匹配规则算是对nginx有了入门,但是这些往往还是不能满足实际的需求场景,例如请求url重写、重定向等等,这都需要对请求的path进行修改操作的,匹配规则是不能独自完成实际需求的,这就需要掌握nginx的另一个常用功能rewrite,下面就来说说这个常用功能。

Rewrite规则

rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。

rewrite只能放在server{}, location{}, if{} 中,并且只能对域名后边传递的参数外的字符串起作用,例如 http://baidu.com/a/we/index.php?id=1&u=str 只对/a/we/index.php重写。语法:

rewrite regex replacement [flag];

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

表面上看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:

  • 执行server块的rewrite指令
  • 执行location匹配
  • 执行选定的location中的rewrite指令

如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

2.1 flag标志位

  • last : 停止执行当前ngx_http_rewrite_module的指令集,但是会继续走一遍请求匹配对应server或者location;
  • break : 停止执行当前ngx_http_rewrite_module的指令集,请求就此完成。
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址

因为301和302不能简单的只返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。

对于上面的flag,有几点需要强调一下:

  • lastbreak对url的重写不会改变地址栏的地址

也就是说,nginx虽然对请求url进行了重写,但是地址栏不会有任何明显的改变,仍然显示nginx重写前的地址;这与redirectpermanent不同。

  • lastbreak的处理策略不同

二者都会终止当前ngx_http_rewrite_module的指令集的执行,但是 last 立即发起新一轮的 请求匹配 而 break 则不会。

  • redirectpermanent会终止后续nginx指令的执行

nginx在rewrite遇到flag是二者时,后续的指令是不会执行的。

server {
    listen 8080;
    location = /test {
        break;
        return 200 $request_uri;
        proxy_pass http://127.0.0.1:8080/other;
    }
    location / {
        return 200 $request_uri;
    }
}

上面例子中,我们访问 curl 127.0.0.1:8080/test,会发现,return 200 $request_uri语句没有执行,而proxy_pass指令被执行了。这是因为:

return指令属于ngx_http_proxy_module模块,它会被break终止掉;而rewrite模块它是ngx_http_proxy_module的指令,不会被break给中断掉。

2.2 if指令与全局变量

if判断指令

语法为if(condition){...} ,对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(conditon)可以是如下任何内容:

  • 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
  • 直接比较变量和内容时,使用=!=
  • ~正则表达式匹配,~*不区分大小写的匹配,!~区分大小写的不匹配

-f!-f用来判断是否存在文件

-d!-d用来判断是否存在目录

-e!-e用来判断是否存在文件或目录

-x!-x用来判断文件是否可执行

例如:

if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite请求到/msid/目录下

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
 } //如果cookie匹配正则,设置变量$id等于正则引用部分

if ($request_method = POST) {
    return 405;
} //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302

if ($slow) {
    limit_rate 10k;
} //限速,$slow可以通过 set 指令设置

if (!-f $request_filename){
    break;
    proxy_pass  http://127.0.0.1;
} //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查

if ($args ~ post=140){
    rewrite ^ http://example.com/ permanent;
} //如果query string中包含"post=140",永久重定向到example.com

location ~* \.(gif|jpg|png|swf|flv)$ {
    valid_referers none blocked www.jefflei.com www.leizhenfang.com;
    if ($invalid_referer) {
        return 404;
    } //防盗链
}

全局变量

下面是可以用作if判断的全局变量:

  • $args : #这个变量等于请求行中的参数,同$query_string
  • $content_length : 请求头中的Content-length字段。
  • $content_type : 请求头中的Content-Type字段。
  • $document_root : 当前请求在root指令中指定的值。
  • $host : 请求主机头字段,否则为服务器名称。
  • $http_user_agent : 客户端agent信息
  • $http_cookie : 客户端cookie信息
  • $limit_rate : 这个变量可以限制连接速率。
  • $request_method : 客户端请求的动作,通常为GET或POST。
  • $remote_addr : 客户端的IP地址。
  • $remote_port : 客户端的端口。
  • $remote_user : 已经经过Auth Basic Module验证的用户名。
  • $request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
  • $scheme : HTTP方法(如http,https)。
  • $server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
  • $server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
  • $server_name : 服务器名称。
  • $server_port : 请求到达服务器的端口号。
  • $request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
  • $uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
  • $document_uri : 与$uri相同。

例如:

例:http://localhost:88/test1/test2/test.php
$host:localhost
$server_port:88
$request_uri:http://localhost:88/test1/test2/test.php
$document_uri:/test1/test2/test.php
$document_root:/var/www/html
$request_filename:/var/www/html/test1/test2/test.php

2.3 常用正则

  • . : 匹配除换行符以外的任意字符
  • ? : 重复0次或1次
  • + : 重复1次或更多次
  • * : 重复0次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的结束
  • {n} : 重复n次
  • {n,} : 重复n次或更多次
  • [c] : 匹配单个字符c
  • [a-z] : 匹配a-z小写字母的任意一个

小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。正则里面容易让人困惑的是\转义特殊字符。

2.4 rewrite实例

例1:

http {
    # 定义image日志格式
    log_format imagelog ‘[$time_local] ‘ $image_file ‘ ‘ $image_type ‘ ‘ $body_bytes_sent ‘ ‘ $status;
    # 开启重写日志
    rewrite_log on;

    server {
        root /home/www;

        location / {
                # 重写规则信息
                error_log logs/rewrite.log notice;
                # 注意这里要用‘’单引号引起来,避免{}
                rewrite ‘^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$‘ /data?file=$3.$4;
                # 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
                set $image_file $3;
                set $image_type $4;
        }

        location /data {
                # 指定针对图片的日志格式,来分析图片类型和大小
                access_log logs/images.log mian;
                root /data/images;
                # 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里
                try_files /$arg_file /image404.html;
        }
        location = /image404.html {
                # 图片不存在返回特定的信息
                return 404 "image not found\n";
        }
}

对形如/images/ef/uh7b3/test.png的请求,重写到/data?file=test.png,于是匹配到location /data,先看/data/images/test.png文件存不存在,如果存在则正常响应,如果不存在则重写tryfiles到新的image404 location,直接返回404状态码。

例2:

rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;

对形如/images/bla_500x400.jpg的文件请求,重写到/resizer/bla.jpg?width=500&height=400地址,并会继续尝试匹配location。

例3:

ssl部分页面加密

2.5 rewrite需要注意的问题

上面说过,rewrite的指令规则为:rewrite regex replacement [flag];

rewrite指令用指定的regex来匹配请求的uri,若匹配成功则用replacement来重写请求uri。这里需要注意的replacement字符串的内容:

1、 若replacement以http://https://或者$scheme开头,则告诉nginx这是重定向操作(flag默认为redirect),nginx则停止处理后续内容,并直接重定向返回给客户端。

location / {
    # 当匹配 正则表达式 /test/(.*)时 请求将被临时重定向到 http://www.baidu.com/$1
    # flag默认为redirect
    rewrite /test/(.*) https://www.baidu.com/$1;
    return 200 ’ok‘; # 此处没有机会执行
}

2、replacement非以上三种情况开头,则就是简单的url重写

location / {
    # 当匹配 正则表达式 /test/(.*)时 请求将被临时重定向到 www.baidu.com/$1
    # flag无值则rewrite会顺序执行
    rewrite /test/(.*) www.baidu.com/$1;
    return 200 ’ok‘; # 此处因为rewrite顺序执行而得到执行机会
}

对于上面两种情况,还需要特别留意一个redirect端口的问题,先上一个例子:

## server.com机器上nginx的配置如下:
server {
    listen 8000;
    location /test1/ {
    rewrite /test1/index.html http://server1.com/demo/test1 redirect;
    }
    location /test2/ {
    rewrite /test2/index.html /demo/test2 redirect;
        proxy_pass http://192.168.1.3:8000;
    }
}

当访问http://server.com/test1/index.html时,会命中/test1的location规则,访问server1.com对应内容一直失败,发现重定向后响应头的Location字段值为http://server1.com:8000/demo/test1,带有8000端口,我们并没有配置,表现的比较诡异?

访问http://server.com/test2/index.html时,命中/test2的location规则,同样访问失败,但是访问的重定向后响应头Location字段值为http://server.com:8000/demo/test2,其带有server.com的server_name和8000的端口,更加诡异?

看到上面的现象,疑惑重重;其实这跟nginx的server_name_in_redirectport_in_redirect指令有关:

在绝对路径中,server_name_in_redirectport_in_redirect 指令表示是否将server块中的 server_name 和 listen 的端口作为redirect用, 重定向的完整url地址根据$schemeserver_name_in_redirectport_in_redirect来确定的。

在绝对路径中,server_name_in_redirect默认是禁用的,而port_in_redirect是默认启用的。对于带有$scheme重定向的绝对路径,nginx会从replacement中获取指定的server_name和port来进行重定向:

第一种,若replacement带请求协议http(s),而其中没有指定port的话,nginx会默认取当前server的listen端口作为重定向的端口。这是上面访问http://server.com/test1/index.html时重定向到http://server.com:8000/demo/test2时会携带8000的原因。

第二种,若replacement不带请求协议http(s),而是相对本地服务器的绝对地址的话,如上面访问http://server.com/test2/index.html的情况,此时server_name_in_redirect由于禁用它会去请求的host来作为server_name,取当前server的listen端口作为重定向的端口,最终重定向到http://server.com:8000/demo/test2

或许你会问,访问http://server.com/test2/index.html为什么不会重定向到http://192.168.1.3:8000/demo/test2上?这是因为rewrite的redirect flag会终止后续指令的执行,所以其后的proxy_pass指令不会执行。

参考

原文地址:https://www.cnblogs.com/wonyun/p/10355574.html

时间: 2024-11-10 07:36:18

前端开发掌握nginx常用功能之rewrite的相关文章

前端开发掌握nginx常用功能之server&location匹配规则

nginx主要是公司运维同学必须掌握的知识,涉及到反向代理.负载均衡等服务器配置.前端开发尤其是纯前端开发来说对nginx接触的并不多,但是在一些情况下,nginx还是需要前端自己来搞:例如我们公司的开发环境和测试环境,虽然qa可以帮助搞定配置,但是每新增一个前端模块或者模块nginx配置经常变更都求着qa搞,麻烦别人还不如自己来搞,这样更能理解自己的需求.这些都需要前端开发对nginx有所理解,下面我们来说说nginx最基础的server和location匹配规则. 1. server匹配规则

五年干货分享!前端开发中最常用的JS代码片段

很多网友私信我,说学到js就开始卡壳了,甚至初略的看了一下js,就跳过开始学习框架之类的.这里要提醒你,js是前端的重中之重,如果你忽视了,后果不堪设想! 学好,并熟练的运用这门编程语言真的很难吗?本篇文章为大家总结了一些前端开发中最常用的JS代码片段,希望能对大家的学习以及工作上都能有所帮助,有所收获. HTML5 DOM 选择器 javascript 代码 // querySelector() 返回匹配到的第一个元素 var item = document.querySelector('.i

前端开发用nginx代理服务器解决服务器跨域问题及跨域访问https访问(mac系统下)

前端开发经常遇到一些服务器由于跨域造成访问不了的情况.以前BS模式,前后端都是一个人开发,跨域问题造成的开发阻碍不是很明显,但是现在前端框架欣欣向荣,很多时候变成了CS模式的开发,但浏览器天生的跨域限制,造成了开发,特别是对单独的前端开发人员(不太懂后台开发的人)造成一定开发障碍.还好有nodejs及其一系列前端自动化工具很好的解决了开发时的问题.但今天我要说的用nginx代理来解决这个问题.我觉得很简单!以下都是基于mac系统的操作!先看没有代理时,随便访问网上一个接口, http://web

前端开发 sublime text 常用插件和配置

前端开发sublimeconfig mac配置 此文件目录中文件主要是关于sublime的插件配置,快捷键配置,主题和字体配置. 插件列表 所有插件都可以使用Package Control安装,具体的安装方法可以自行谷歌安装,不在本文的介绍范围之内.也可以是使用git 手动安装. 1.autoprefixer 该插件主要使编写css更加的方便和快捷,可以配置快捷键给标签属性添加浏览器厂商前缀.安装前需要确定电脑安装node. 配置快捷键如下: //autoprefixer快捷键设置 { "key

22,Nginx常用功能模块

1,Nginx常用模块(日志切割)1)我们可以在虚拟主机配置定义不同网站日志放到以自己名字命名的日志文件里2)systemctl reload nginxcd /var/log/nginx && ll 4)切割日志,让日志按照每天日期去命名5,logrotate -f /etc/logrotate.d/nginx 切割2,查看Nginx状态模块1)cd /etc/nginx/conf.d2)systemctl restart nginx3)curl www.oldzhang.comrequ

Nginx常用功能配置及优化

---------------------------------------------------------------------------------------- 规范优化Nginx配置文件: ---------------------------------------------------------------------------------------- Nginx的主配置文件为nginx.conf,主配置文件包含所有虚拟主机的子配置文件同一放到extra目录中. 虚

web前端开发企业级CSS常用命名,书写规范总结

1.常用命名 标题: title 摘要: summary 箭头: arrow 商标: label 网站标志: logo 转角/圆角: corner 横幅广告: banner 子菜单: subMenu 搜索:search 搜索框: searchBox 登录: login 登录条:loginbar 工具条: toolbar 下拉: drop 标签页: tab 当前的: current 列表: list 滚动:scroll 服务: service 提示信息: msg 热点:hot 新闻: news 小

nginx常用功能配置

一.规范优化nginx配置文件 nginx的主配置文件为nginx.conf,主配置文件包含的所有虚拟主机的子配置文件会统一放入extra目录中,虚拟主机的配置文件按照网站的域名或功能取名,例如www.conf.bbs.conf.blog.conf等.当然,如果虚拟主机的数量不是很多,也可以把多个虚拟主机配置成一个单独的配置文件,仅仅和nginx的主配置文件 nginx.conf分离开即可. 这里使用的参数是include,下面先看看它的语法: include file | mask 它可以放置

Nginx常用功能举例解析

01. 静态HTTP服务器 说明 Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML.图片)通过HTTP协议展现给客户端. 配置 每个人配置文件路径可能会不同,但格式一样. [[email protected]]# vim /etc/nginx/nginx.conf server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main