在这篇博客文章中,我们将讨论如何创建NGINX重写规则(相同的方法适用于NGINX Plus和开源NGINX软件)。重写规则会更改客户端请求中的部分或全部URL,通常用于以下两种目的之一:
- 通知客户他们请求的资源现在位于不同的位置。示例用例是指您的网站的域名已更改,您希望客户端使用规范的URL格式(带或不带www前缀),以及何时想要捕获并纠正域名的常见拼写错误。返回和重写指令适用于这些目的。
- 控制NGINX和NGINX Plus中的处理流程,例如在需要动态生成内容时将请求转发到应用程序服务器。 try_files指令通常用于此目的。
注意:要了解如何将Apache HTTP服务器重写规则转换为NGINX重写规则,请参阅我们的配套博客文章“将Apache重写规则转换为NGINX重写规则”。
我们假设您熟悉HTTP响应代码和正则表达式(NGINX和NGINX Plus使用Perl语法)。
比较return,rewrite和try_files指令
通用NGINX重写的两个指令是return和rewrite,try_files指令是将请求定向到应用程序服务器的便捷方式。让我们回顾一下指令的作用以及它们的区别。
return指令
return指令比两个通用指令更简单,因此我们建议在可能的情况下使用它而不是重写(稍后会详细说明原因和时间)。将返回包含在指定要重写的URL的服务器或位置上下文中,并定义客户端在将来对资源的请求中使用的更正(重写)URL。
这是一个将客户端重定向到新域名的非常简单的示例:
server {
listen 80;
listen 443 ssl;
server_name www.old-name.com;
return 301 $scheme://www.new-name.com$request_uri;
}
listen指令表示服务器块适用于HTTP和HTTPS流量。 server_name指令匹配域名为www.old-name.com的请求URL。 return指令告诉NGINX停止处理请求并立即将代码301(永久移动)和指定的重写URL发送到客户端。重写的URL使用两个NGINX变量来捕获和复制原始请求URL中的值:$ scheme是协议(http或https),$ request_uri是包含参数的完整URI。
对于3xx系列中的代码,url参数定义新的(重写的)URL。
return (301 | 302 | 303 | 307) url;
对于其他代码,您可以选择定义出现在响应正文中的文本字符串(HTTP代码的标准文本,例如404中未找到,仍包含在标题中)。文本可以包含NGINX变量。
return (1xx | 2xx | 4xx | 5xx) ["text"];
例如,在拒绝没有有效身份验证令牌的请求时,此指令可能适用:
return 401 "Access denied because token is expired or invalid";
您还可以使用几个语法快捷方式,例如省略代码(如果是302);请参阅return指令的参考文档。
(在某些情况下,您可能希望返回比在文本字符串中实现的更复杂或细微差别的响应。使用error_page指令,您可以为每个HTTP代码返回完整的自定义HTML页面,以及更改响应代码或执行重定向。)
因此,返回指令易于使用,并且在重定向满足两个条件时是合适的:重写的URL适用于与服务器或位置块匹配的每个请求,并且您可以使用标准NGINX变量构建重写的URL。
rewrite指令
但是,如果您需要测试URL之间更复杂的区别,捕获原始URL中没有相应NGINX变量的元素,或者更改或添加路径中的元素,该怎么办?在这种情况下,您可以使用重写指令。
与return指令一样,您将rewrite指令括在服务器或位置上下文中,该上下文定义了要重写的URL。否则,这两个指令比相似的更加不同,并且重写指令可能更复杂,无法正确使用。它的语法很简单:
rewrite regex URL [flag];
但是第一个参数regex意味着NGINX Plus和NGINX只有在匹配指定的正则表达式时才会重写URL(除了匹配服务器或位置指令)。附加测试意味着NGINX必须进行更多处理。
第二个区别是重写指令只能返回代码301或302.要返回其他代码,您需要在重写指令后包含一个return指令(请参阅下面的示例)。
最后,重写指令不一定会像返回那样停止NGINX对请求的处理,并且它不一定会向客户端发送重定向。除非你明确指出(带有标志或URL的语法)你希望NGINX停止处理或发送重定向,否则它会在整个配置中运行,寻找在Rewrite模块中定义的指令(break,if,return,rewrite) ,并设置),并按顺序处理它们。如果重写的URL与Rewrite模块中的后续指令匹配,则NGINX会对重写的URL执行指示的操作(通常会再次重写)。
这是事情变得复杂的地方,您需要仔细计划如何订购指令以获得所需的结果。例如,如果原始位置块和其中的NGINX重写规则与重写的URL匹配,则NGINX可以进入循环,将重写一遍又一遍地应用到内置限制10次。要了解所有详细信息,请参阅“重写”模块的文档。如前所述,我们建议您尽可能使用return指令。
这是一个使用rewrite指令的NGINX重写规则示例。它匹配以字符串/ download开头的URL,然后在路径后面的某处包含/ media /或/ audio /目录。它用/ mp3 /替换这些元素,并添加适当的文件扩展名.mp3或.ra。 $ 1和$ 2变量捕获不变的路径元素。例如,/ download / cdn-west / media / file1变为/download/cdn-west/mp3/file1.mp3。如果文件名有扩展名(例如.flv),则表达式将其删除并将其替换为.mp3。
server {
# ...
rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last;
return 403;
# ...
}
我们在上面提到过,您可以向重写指令添加标志以控制处理流程。示例中的最后一个标志是其中之一:它告诉NGINX跳过当前服务器或位置块中的任何后续Rewrite-module指令,并开始搜索与重写的URL匹配的新位置。
此示例中的最终返回指令意味着如果URL与rewrite指令不匹配,则将代码403返回给客户端。
try_files指令
与return和rewrite指令一样,try_files指令放在服务器或位置块中。作为参数,它采用一个或多个文件和目录的列表以及最终URI:
try_files file ... uri;
NGINX按顺序检查文件和目录是否存在(从根和别名指令的设置构建每个文件的完整路径),并为它找到的第一个服务器提供服务。要指示目录,请在元素名称的末尾添加斜杠。如果不存在任何文件或目录,NGINX将执行内部重定向到最终元素(uri)定义的URI。
要使try_files指令起作用,还需要定义捕获内部重定向的位置块,如以下示例所示。最终元素可以是命名位置,由初始符号(@)表示。
try_files指令通常使用$ uri变量,该变量表示域名后面的URL部分。
在以下示例中,如果客户端请求的文件不存在,NGINX将提供默认的GIF文件。当客户端请求(例如)http://www.domain.com/images/image1.gif时,NGINX首先在由适用于该位置的根或别名指令指定的本地目录中查找image1.gif(未显示)在摘录中)。如果image1.gif不存在,NGINX会查找image1.gif /,如果不存在,则会重定向到/images/default.gif。该值与第二个位置指令完全匹配,因此处理停止并且NGINX为该文件提供服务并将其标记为缓存30秒。
location /images/ {
try_files $uri $uri/ /images/default.gif;
}
location = /images/default.gif {
expires 30s;
}