顾名思义,rewrite 就是重定向,就是将收到的请求依据配置重定向成为另一个请求并返回。 nginx、Apache 都提供了强大的 rewrite 功能,在实际使用中,也十分的方便,比如消息的转发或网站默认页面或出错页面的处理等。 ngx_http_rewrite_module 模块实现了对 url 的判断、正则匹配、重定向。
nginx 配置文件中可以使用很多变量,rewrite 的规则就是在配置文件中定义的,因此,首先了解 nginx 有哪些预定义变量更加有利于我们去了解和配置 rewrite 规则。 nginx 配置中可以出现的变量,同时也可以通过 set 指令创建变量。 可以通过第三方模块 echo-nginx-module 查看配置中 相应变量的值。
预定义变量 | 意义 |
---|---|
arg_PARAMETER | GET请求中变量名PARAMETER参数的值 |
args | GET请求中的参数,如foo=123&bar=blahblah |
binary_remote_addr | 二进制码形式的客户端地址 |
body_bytes_sent | 传送页面的字节数 |
content_length | 请求头中的Content-length字段 |
content_type | 请求头中的Content-Type字段 |
cookie_COOKIE | cookie COOKIE的值 |
document_root | 当前请求在root指令中指定的值 |
document_uri | 与$uri相同 |
host | 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称 |
hostname | 机器名使用 gethostname系统调用的值 |
http_HEADER | HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_ |
sent_http_HEADER | HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_ |
sent_http_content_type | 响应头中的 CONTENT-TYPE 字段 |
is_args | 如果$args设置,值为"?",否则为"" |
limit_rate | 这个变量可以限制连接速率 |
nginx_version | 当前运行的nginx版本号 |
query_string | 与$args相同 |
remote_addr | 客户端的IP地址 |
remote_port | 客户端的端口 |
remote_user | 已经经过 ngx_auth_basic_module 验证的用户名 |
request_filename | 当前连接请求的文件路径,由root或alias指令与URI请求生成 |
request_body | 请求体,主要用于 proxy_pass 或 fastcgi_pass |
request_body_file | 客户端请求主体信息的临时文件 |
request_completion | 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空 |
request_method | 这个变量是客户端请求的动作,如GET或POST |
request_uri | 包含一些客户端请求参数的原始URI,它无法修改 |
scheme | 所用的协议,比如http或者是https |
server_addr | 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数 |
server_name | 服务器名称 |
server_port | 请求到达服务器的端口号 |
server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1 |
uri | 请求中的当前URI(不带请求参数,参数位于$args),不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,如 /foo/bar.html |
proxy_add_x_forwarded_for | 获取的是客户端的真实ip地址 |
proxy_host | 获取upstream的上游代理名称,例如upstream backend |
proxy_port | 要代理到的端口 |
proxy_protocol_addr | 代理头部中客户端的ip地址,或者是一个空的字符串 |
upstream_addr | 代理到上游的服务器地址信息 |
upstream_cache_status | proxy的缓存状态,例如这里第一次访问为MISS,第二次访问时为HIT |
upstream_response_length | 上游服务器响应报文的长度 |
upstream_response_time | 上游服务器响应的时间 |
upstream_status | 上游服务器响应的状态码 |
上述过程可能会嵌套、重复执行,如果 rewrite 次数达到 10 次,就会返回 500 Internal Server Error。
停止执行当前虚拟主机的后续 rewrite 指令集。 如:
if ($slow) {
limit_rate 10k;
break;
}
对给定条件 condition 进行判断,如果为真,则执行大括号内的 rewrite 指令。
if (condition)
{
...
}
如:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($request_method = POST) {
return 405;
}
if ($slow) {
limit_rate 10k;
}
if ($invalid_referer) {
return 403;
}
if 指令的 condition 可以是下列中的任何内容:
条件 | 判断内容 |
---|---|
变量 | 如果变量值为空字符串或以 0 开始的字符串则为 false |
=、!= | 比较一个变量和字符串是否相等 |
~、~* | 使用正则表达式匹配变量 |
-f、!-f | 检查一个文件是否存在 |
-d、!-d | 检查一个目录是否存在 |
-e、!-e | 检查一个文件、目录、符号链接是否存在 |
-x、!-x | 检查一个文件是否可执行 |
用来停止处理并返回状态或 URL。
return code;
return URL;
rewrite regex replacement [flag];
如果一个URI匹配指定的正则表达式regex,URI就按照replacement重写。 flag 取值如下:
如:
server {
...
rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra last;
return 403;
...
}
如果在 rewrite 的 URL 最后加一个 ?,则说明在 rewrite 后去掉原请求的所有参数。
rewrite ^/users/(.*)$ /show?user=$1? last;
创建自定义变量。
set variable value;
开启或关闭以notice级别打印rewrite处理日志到error log文件,可以出现在 main、server、location 配置的任何位置。
rewrite_log on|off;
控制是否输出为初始化的变量到日志。
uninitialized_variable_warn on|off;
通过判断 URI 中是否有 ’、;、>、< 等字符可以快速过滤掉可能发生 SQL 注入的请求,然后直接返回 404 Not Found。
if ( $query_string ~* ".*[;'<>].*" ) {
return 404;
}
下面这个配置来源于 php 框架 Symfony 手册,用来隐藏作为入口的 app.php。 所有请求全部被重定向到 app.php 下。
server {
listen 80;
server_name example.com; # 域名
root /var/www/symfony2/web; # 站点根目录
error_log /var/log/nginx/symfony2.error.log;
access_log /var/log/nginx/symfony2.access.log;
# 如果URL中包含app.php,则转发为伪静态格式
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
# 此段为将PHP请求转交给FastCGI服务,PHP-FPM是非常流行的选项。
location ~ ^/(app|app_dev)\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /app.php break;
}
}