.htaccess和HttpRewrite是新手经常容易犯错的地方,最近遇到这个问题也比较多,老九正好就把收藏的东西整理了一下。主要还是根据官方文档,补足些许翻译工作,后续有心得会再补充。另外Nginx各个版本也有细微区别,具体问题请具体分析。
HttpRewrite模块
该模块允许使用正则表达式改变URI,并且根据变量来转向以及选择配置。
如果在server级别设置该选项,那么他们将在location之前生效。如果在location还有更进一步的重写规则,location部分的规则依然会被执行。如果这个URI重写是因为location部分的规则造成的,那么location部分会再次被执行作为新的URI。
这个循环会执行10次,然后Nginx会返回一个500错误。
指令集:
[#break break]
[#if if]
[#return return]
[#rewrite rewrite]
[#set set]
[#uninitialized_variable_warn uninitialized_variable_warn]
break
语法: break
默认值: none
作用域: server, location, if
作用是完成当前的规则列
示例:
if ($slow) {
: limit_rate 10k;
: break;
}
if
语法: if (condition) { ... }
默认: none
作用域: server, location
检查条件的真值。如果条件评估为true,则执行花括号中指示的代码,并根据下一个块内的配置处理请求。如果从上一级继承,则指令内的配置。
可以被分配的条件:
- 变量的名称,错误值为:空字符串“”,或任何以“0”开头的字符串;
- 变量与使用“=”和“!=”等运算符进行比较的行;
- 与使用符号的正则表达式匹配的模式“~*”和“~”,其中,'〜' 含义为符合,但是大小写敏感;而〜*大小写不敏感。而“!~”和“!~*”意思相反,表示“不匹配”;
- 使用-f以及!-f检测一个文件是否存在;
- 使用-d以及!-d检测一个目录是否存在;
- 使用-e以及!-e检测是否存在一个文件,一个目录或者一个符号链接;
- 使用-x以及!-x检测一个文件是否可执行;
注:正则表达式的部分可以放在括号中,然后可以在 $1 to $9 变量中访问其值。
实例:
if ($http_user_agent ~ MSIE) {
: rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
: set $id $1;
}
if ($request_method = POST ) {
: return 405;
}
if (!-f $request_filename) {
: break;
: proxy_pass http://127.0.0.1;
}
if ($slow) {
: limit_rate 10k;
}
if ($invalid_referer) {
: return 403;
}
特别的,内建变量的值$invalid_referer,是由指令有效的引用者给出的。
return
语法: return code
默认值: none
作用域: server, location, if
This directive concludes execution of the rules and returns the status code indicated to client. It is possible to use the following values: 204, 400, 402-406, 408, 410, 411, 413, 416 and 500-504. Furthermore, nonstandard code 444 closes the connection without sending any headers.
这个指令根据规则的执行情况,返回一个状态值给客户端。可使用值包括:204,400,402-406,408,410,411,413,416以及500-504。也可以发送非标准的444代码-未发送任何头信息下结束连接。
rewrite
语法: rewrite regex replacement flag
默认: none
作用域: server, location, if
这个指令根据表达式来更改URI,或者修改字符串。指令根据配置文件中的顺序来执行。
注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句,如下:
if ($host ~* www\.(.*)) {
: set $host_without_www $1;
: rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}
flag使结束重写指令的执行成为可能。如果替换字符串以http://为头,客户端将被重定向,任何进一步的重写指令将被终止。
flag可以是下列任何一种:
last - 完成重写指令的处理,然后搜索相应的URI和位置
break - 完成重写指令的处理
redirect - 返回临时重定向,代码302;如果替换字符串是以http://开始的,redirect将被使用
permanent - 返回代码301的永久重定向
注意,如果重定向是相对的(没有主机部分),那么当重定向Nginx时,如果头匹配server_name指令的名称或server_name指令的名称(如果头不匹配或不存在),则使用“host”头。
如果标题不匹配或不存在,如果没有设置server_name,则使用本地主机名。如果希望Nginx始终使用“Host”标头,则可以使用通配符“*”server_name(但是要查看这样做的限制)。
例如:
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
但是如果我们把这些指令放在location /download/中,那么就需要用break来替换last标志,否则nginx会达到10个周期的限制,返回错误500:
location /download/ {
: rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
: rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;
: return 403;
}
如果在替换参数行中被指定,那么请求参数的其余部分将被附加上。为了避免添加它们,在最后一个字符上加上问号:
: rewrite ^/users/(.*)$ /show?user=$1? last;
注: 对花括号( { 和 } )来说, 他们既能用在重定向的正则表达式里,也是用在配置文件里分割代码块, 为了避免冲突, 正则表达式里带花括号的话,应该用双引号(或者单引号)包围。比如,要将类似以下的url:
/photos/123456
重定向到:
/path/to/photos/12/1234/123456.png
可以用以下方法 (注意双引号):
rewrite "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png;
set
语法: set variable value
默认值:无
作用域: server, location, if
指令为所指示的变量建立值。值可以使用文本、变量及其组合。
uninitialized_variable_warn
语法: uninitialized_variable_warn on|off
默认值: uninitialized_variable_warn on
作用域:http, server, location, if
启用或禁用关于未初始化变量的警告的日志记录。
在内部,重写指令在将配置文件加载到内部代码时编译,在解释器请求时可用。
这个解释器是一个简单的堆栈虚拟机。例如下面的指令
location /download/ {
: if ($forbidden) {
: return 403;
: }
: if ($slow) {
: limit_rate 10k;
: }
: rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;
}
将被编译成这个序列:
: variable $forbidden
: checking to zero
: recovery 403
: completion of entire code
: variable $slow
: checking to zero
: checkings of regular expression
: copying "/"
: copying $1
: copying "/mp3/"
: copying $2
: copying "..mpe": completion of regular expression
: completion of entire sequence