如何使用Nginx的rewrite(重写)?

Nginx

1 基础知识

1.1 重写的概念

重写规则会更改客户端请求中的部分或全部URL

1.2 使用场景

– 使用return和rewrite指令将客户端请求的资源重新定位到不同的位置(例如域名跳转,规范客户端的URL格式,捕获并纠正域名的拼写错误)
– 使用try_files指令控制处理流程,将请求转到需要的应用程序服务器

1.3 return指令

1.3.1 使用范例

server {
    listen 80;
    listen 443 ssl;
    server_name www.cmdschool.org;
    return 301 $scheme://www.cmdschool.org$request_uri;
}

指令解析,
– listen指令标记server块适用于http与https两种协议的流量
– server_name指令标记只匹配www.cmdschool.org的URL请求
– return指令让Nginx停止处理请求并立刻返回301代码(Moved Permanently)和将重定向的URL发送到客户端
– 重写的URL使用Nginx变量来捕获和复制原始的URI值,$scheme代表http和https协议,$request_uri代表完整的URI参数

1.3.2 返回URL的格式

return (301 | 302 | 303 | 307) url;

1.3.3 返回字符串的格式

return (1xx | 2xx | 4xx | 5xx) ["text"];

例如,我们需要拒绝无效身份验证令牌的请求,

return 401 "Access denied because token is expired or invalid";

1.3.4 模块的说明文档

如果需要更加详细的模块使用方法,请参阅以下文档,
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return
另外,如果需要返回错误也,请参考以下文档,
http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page

1.3.5 使用条件

– 重写的URL匹配server与location模块的请求
– 适用于使用标准的Nginx变量构建简单地重写的URL

1.4 rewrite指令

1.4.1 使用条件

– 适用于没有标准Nginx变量的情况下更改URL或添加URL元素

1.4.2 使用语法

rewrite regex URL [flag];

详细的指令解析如下,
– regex参数声明只有匹配指定的正则表达式时才会重写URL
– regex也意味着指令只能返回301或302的代码,要返回其他代码,需要在return指令后包含另外一个重写指令
– rewrite指令不一定会停止对请求的处理或会向客户端发送重定向(除非flag与URL有明确的声明)
– 如果需要停止或发送重定向,需要配合break, if, return, rewrite和set定义使用
– Nginx有防止匹配条件的无限重写机制(Nginx内置限制为10次)

1.4.3 使用范例

server {
    # ...
    rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra  last;
    return  403;
    # ...
}

– 范例匹配以“/download”开头的并后面包含“/media”与“/audio”的URL
– 范例“$1”与“$2”代表变量捕获并没有改变的请求路径
– 范例使用“$1”变量值等于“^(/download/.*)”字符串匹配的格式,其中“.*”匹配任意路径
– 范例使用使用“/mp3”替换掉请求的“/media”或“/audio”
– 范例带变量字符串“$2.mp3”或“$2.ra”的值等于“(\w+)\.?.*$”匹配的格式,其中“\w+”匹配任意字符,“.?”匹配“.”
– 假设请求路径为“/download/cdn-west/media/file1”,则重写为“/download/cdn-west/mp3/file1.mp3”
– 请求路径是用户输入浏览器的路径,重写的路径是相对于站点根目录路径(相对路径)
– “last”标志用于控制处理流程,告诉NGINX跳过当前server或location模块中的任何后续的重写指令(只匹配一次)

1.4.4 模块的说明文档

如果需要更加详细的模块使用方法,请参阅以下文档,
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite

1.5 try_files指令

1.5.1 使用范例

location /images/ {
    try_files $uri $uri/ /images/default.gif;
}

location = /images/default.gif {
    expires 30s;
}

– 范例判断客户端请求的文件不存在,则提供默认的GIF文件
– 假设客户端请求http://www.cmdschool.org/images/image1.gif时,Nginx首先查找location定义目录“/images”
– 如果“images1.gif”不存在,Nginx会查找“image1.gif/”,如果不存在,则重写为“/images/default.gif”
– 该值同时匹配第二个指令,Nginx停止文件服务并标记为缓存30秒
– 范例变量“$uri”代表域名后面的URI,如“http://www.cmdschool.org/images/image1.gif”中的“/images/image1.gif”

1.5.2 使用语法

try_files file ... uri;

– try_files指令与return和rewrite指令一样,上下文适用于server或location模块
– try_files指令按顺序检查文件或目录的存在(根据root和alias的值构建每个文件的完整路径)
– 如果文件或目录不存在,Nginx将路径重写为URI定义的值
– 如果要定义目录,请在file的值末尾加“/”

2 使用范例

2.1 标准化域名

2.1.1 旧域名重定向为新域名

server {
    listen 80;
    listen 443 ssl;
    server_name www.cmdschool.com www.cmdschool.net www.cmdschool.cn;
    return 301 $scheme://www.cmdschool.org$request_uri;
}

– 范例将域名“www.cmdschool.com”、“www.cmdschool.net”与“www.cmdschool.cn”重定向为“www.cmdschool.org”
– 变量“$scheme”代表原始的协议(HTTP与HTTPS)
– 变量“$request_uri”代表请求的URI
以上适用于旧站点与新站点的URI一一对应,如果不对应,应当使用如下范例,

server {
    listen 80;
    listen 443 ssl;
    server_name www.cmdschool.com www.cmdschool.net www.cmdschool.cn;
    return 301 $scheme://www.cmdschool.org;
}

如果使用rewrite,应当参照如下范例书写,

# NOT RECOMMENDED
rewrite ^ $scheme://www.cmdschool.org$request_uri permanent;

– 范例的指令要比return效率要低(因为需要Nginx处理正则表达式)
– “^”匹配完整的原始URL
– return相对rewrite更加容易阅读(返回码格式,即“return 301”表达更明确)

2.1.2 添加或删除www前缀

# add 'www'
server {
    listen 80;
    listen 443 ssl;
    server_name domain.com;
    return 301 $scheme://www.cmdschool.org$request_uri;
}
# remove 'www'
server {
    listen 80;
    listen 443 ssl;
    server_name www.cmdschool.org;
    return 301 $scheme://cmdschool.org$request_uri;
}

如果使用rewrite,应当参照如下范例书写,

# NOT RECOMMENDED
rewrite ^(.*)$ $scheme://www.cmdschool.org$1 permanent;

2.1.3 将所有流量重定向到指定的域名

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    return 301 $scheme://www.cmdschool.org;
}

– 范例匹配Nginx接收到任何匹配的域名(适用于防止域名拼写错误,即域名通配)
– 范例通过“listen”指令的“default_server”参数与server_name指令指定参数“_”实现通配
– 范例通过省略“$request_uri”将请求重定向到主页

2.1.4 强制所有请求使用SSL/TLS

server {
    listen 80;
    server_name www.cmdschool.org;
    return 301 https://www.cmdschool.org$request_uri;
}

– 范例将80端口的请求强制重定向到https对应的URL
– 范例使用“$request_uri”变量捕获的URI
如果使用rewrite,应当参照如下范例书写,

# NOT RECOMMENDED
if ($scheme != "https") {
    rewrite ^ https://www.cmdschool.org$uri permanent;
}

2.1.5 为WordPress网站启用漂亮的永久链接

location / {
    try_files $uri $uri/ /index.php?$args;
}

– 范例如果文件或目录不存在,Nginx则重定向到“/index.php”并传递查询查询字符串参数
– 范例中参数使用“$args”变量捕获

2.1.6 拒绝请求不支持的文件扩展名

location ~ .(aspx|php|jsp|cgi)$ {
    return 410;
}

– 范例中返回码“410”明确指出资源永久不可用(因此客户端不会再次发送请求)
– 另外,返回码“404”则表示资源暂时不可用
如果需要返回“403”或“Server handles only Ruby requests”之类的字符串以提供更准确的失败原因,则可参照如下范例书写,

location ~ .(aspx|php|jsp|cgi)$ {
    deny all;
}

2.1.7 配置自定义重写路由

rewrite ^/listings/(.*)$ /listing.html?listing=$1 last;

注:范例将友好URL如“http://www.cmdschool.org/listings/123”重写为“http://www.cmdschool.org/listing.html?listing=123”

2.2 重写结合代理

location /admin {
       proxy_pass             https://admin.cmdschool.org/;
       rewrite                /admin/(.*) /$1 break;
       proxy_cache            off;
       proxy_cache_valid      200  1d;
       proxy_cache_use_stale  error timeout invalid_header updating
                                  http_500 http_502 http_503 http_504;
}

参阅文档:
================

官方重写的介绍
—————-
https://www.nginx.com/blog/creating-nginx-rewrite-rules/

官方Apache与Nginx的重写转换
————————–
https://www.nginx.com/blog/converting-apache-to-nginx-rewrite-rules/

Nginxi的正则表达式(perl)
————————
http://perldoc.perl.org/perlre.html#Regular-Expressions

没有评论

发表评论

Nginx
如何解决Nginx代理传大文件不同步问题?

1 前言 一个问题,一篇文章,一出故事。 笔者生产环境遇到用户透过反向代理上传大文件提示用户已经完成 …

Nginx
如何实现Nginx根据路径分配代理?

1 前言 一个问题,一篇文章,一出故事。 笔者生产环境遇到需要根据URI路径选择走哪个代理服务器的案 …

Nginx
如何实现Nginx返回字符串或变量值?

1 前言 一个问题,一篇文章,一出故事。 笔者测试环境中经常需要返回Nginx变量的具体值,于是整理 …