rewrite模块即ngxhttprewrite_module模块,主要功能是改写请求URI,是nginx默认安装的模块,用于重写url进行内部跳转和重定向等。
rewrite模块的指令有break, if, return, rewrite, set等,其中rewrite是比较关键的。
指令语法:rewrite regex replacement[flag];
简单的小例子:
rewrite ^/(.*) http://www.baidu.com/ permanent; # 匹配成功后跳转到百度,执行永久301跳转
regex是PCRE 风格的,如果regex匹配URI,那么URI就会被替换成replacement,replacement 就是新的URI。如果rewrite同一个上下文中有多个这样的正则,匹配会依照rewrite指令出现的顺序先后依次进行下去,匹配到一个之后并不会终止,而是继续往下匹配,直到返回最后一个匹配上的为止。如果想要中止继续往下匹配,可以使用第三个参数flag。
字符 | 描述 |
---|---|
\ | 将后面接着的字符标记为一个特殊字符或者一个原义字符或一个向后引用 |
^ | 匹配输入字符串的起始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的字符零次或者多次 |
+ | 匹配前面字符串一次或者多次 |
? | 匹配前面字符串的零次或者一次 |
. | 匹配除“\n”之外的所有单个字符 |
(pattern) | 匹配括号内的pattern |
要替换的url
标记符号 | 说明 |
---|---|
last | 本条规则匹配完成后继续向下匹配新的location URI规则 |
break | 本条规则匹配完成后终止,不在匹配任何规则 |
redirect | 返回302临时重定向 |
permanent | 返回301永久重定向 |
rewrite ^/users/(.*)$ /show?user=$1? last;
生成的url是/show?user=xxx
如果想带上旧url上的参数,则不加?
rewrite ^/users/(.*)$ /show?user=$1 last;
生成的url为/show?user=xxx&abc=xxx
server中:
server {
...
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png last;
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png last;
return 403; #没有匹配上,那就返回403
...
}
location中:
location /download/ {
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png break;
rewrite ^(/download/.*)/show/(.*)\..*$ $1/mp3/$2.png break;
return 403;
}
上下文:server, location, if
停止处理任何rewrite的相关指令。如果出现在location里面,那么所有后面的rewrite模块指令都不会再执行,也不发起内部重定向,而是直接用新的URI进一步处理请求。
基本语法:if (condition) { ... }
上下文:server, location
根据条件condition的真假决定是否加载{...}中的配置,{...}中的配置可以继承外面的配置,也可以对外面已有配置指令进行覆写。
条件 | 判断内容 |
---|---|
变量 | 如果变量值为空字符串或以 0 开始的字符串则为 false |
=、!= | 比较一个变量和字符串是否相等 |
~、~* | 使用正则表达式匹配变量 |
-f、!-f | 检查一个文件是否存在 |
-d、!-d | 检查一个目录是否存在 |
-e、!-e | 检查一个文件、目录、符号链接是否存在 |
-x、!-x | 检查一个文件是否可执行 |
如: -f /path/to 检验文件是否存在;!-f /path/to 检验文件是否不存在
当condition为变量$var本身时,当且仅当变量值为空字符或者0时,条件为false,其余情况皆为 true。 可以用变量$var通过"="或者"!="与字符串相比较,即$var = xxx或者$var != xxx,也可以匹配正则表达式。
基本语法:return code [text];或者return code URL;或者return URL;
上下文:server, location, if
停止任何的进一步处理,并且将指定状态码返回给客户端。如果状态码为444(此状态码是非标准的),那么直接关闭此TCP连接。
return的参数有四种形式:
官方解释:
Stops processing and returns the specified code to a client. The non-standard code 444 closes a connection without sending a response header.
Starting from version 0.8.42, it is possible to specify either a redirect URL (for codes 301, 302, 303, 307, and 308) or the response body text (for other codes). A response body text and redirect URL can contain variables. As a special case, a redirect URL can be specified as a URI local to this server, in which case the full redirect URL is formed according to the request scheme ($scheme) and the server_name_in_redirect and port_in_redirect directives.
In addition, a URL for temporary redirect with the code 302 can be specified as the sole parameter. Such a parameter should start with the “http://”, “https://”, or “$scheme” string. A URL can contain variables.
Only the following codes could be returned before version 0.7.51: 204, 400, 402 — 406, 408, 410, 411, 413, 416, and 500 — 504.
The code 307 was not treated as a redirect until versions 1.1.16 and 1.0.13.
The code 308 was not treated as a redirect until version 1.13.0.
见:http://nginx.org/en/docs/http/ngxhttprewrite_module.html
基本语法:set $variable value;
上下文:server, location, if
这是一个有用的指令,用来定义变量,变量的值可以包含字符串,另外的变量或者是二者结合。
set $var = $http_x_forwarded_for;
基本语法:rewrite_log on | off;
上下文:http, server, location, if
如果开启 on,那么当发生rewrite时,会产生一个notice级别的日志;否则不会产生任何日志。默认情况下是不产生的,但在调试的时候可以将其置为on。
这些变量可以用于上述指令中,也可用于输出日志
示例1: server中:
server {
...
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png last;
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png last;
return 403; #没有匹配上,那就返回403
...
}
示例2: location中:
location /download/ {
rewrite ^(/download/.*)/show/(.*)\..*$ $1/img/$2.png break;
rewrite ^(/download/.*)/show/(.*)\..*$ $1/mp3/$2.png break;
return 403;
}
示例3 :
if( !-e $request_filename )
{
rewrite ^/(.*)$ index.php last;
}
当访问的文件和目录不存在时,重定向到某个php文件
示例4 :
rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
目录对换 /123456/xxxx ====> /xxxx?id=123456
示例5 :
if( $http_user_agent ~ MSIE)
{
rewrite ^(.*)$ /ie/$1 break;
}
如果客户端使用的是IE浏览器,则重定向到/ie目录下
示例6
location ~ ^/(cron|templates)/
{
deny all;
break;
}
禁止访问多个目录
示例7:
location ~ .*\.(sh|flv|mp3)$
{
return 403;
}
禁止访问以.sh,.flv,.mp3为文件后缀名的文件
示例8:
location ~ ^/data
{
deny all;
}
禁止访问以/data开头的文件
示例9:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)$
{
expires 1h;
}
设置某些类型文件的浏览器缓存时间
示例10:
location ^~ /html/scripts/loadhead_1.js {
access_log off;
root /opt/lampp/htdocs/web;
expires 600;
break;
}
设定某个文件的过期时间;这里为600秒,并不记录访问日志
示例11:
location ~(favicon.ico) {
log_not_found off;
expires 99d;
break;
}
location ~(robots.txt) {
log_not_found off;
expires 7d;
break;
}
给favicon.ico和robots.txt设置过期时间;这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志
示例12:
location ~* ^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
valid_referers none blocked *.nixi8.com nixi8.com localhost 192.168.1.208; #定义none(空,直接访问),blocked(被防火墙标记过的来路),
nixi8.com的二级域名和一级域名,localhost,192.168.1.208
if ($invalid_referer) { # 如果不是上面定义的其中一个
rewrite ^/ http://www.nixi8.com/none.gif; # 就重写到一张gif图片上;
return 412;
break;
}
access_log off; # 关闭日志,降低服务器的损耗
root /opt/lampp/htdocs/web;
expires 3d; //所有文件3天缓存
break;
}
图片防盗链。
示例13:
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}
目录自动加/:用([^/])匹配最后一个非'/'的字符,然后自己强行再添加一个'/'($2变量后的那个)
示例14:
root /opt/htdocs/www;
allow 208.97.167.194;
allow 222.33.1.2;
allow 231.152.49.4;
deny all;
auth_basic “C1G_ADMIN”;
auth_basic_user_file htpasswd;
只允许固定ip访问网站,并加上密码。
示例15:
rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /job/$1/$2/jobshow_$3.html last;
将多级目录下的文件转成一个文件,增强seo效果/job-123-456-789.html 指向/job/123/456/789.html
示例16:将根目录下某个文件夹指向2级目录
如/shanghaijob/ 指向 /area/shanghai/
如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
上面例子有个问题是访问/shanghai时将不会匹配
rewrite ^/([0-9a-z]+)job$ /area/$1/ last;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。
那我加上自动跳转也是不行咯
(-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/permanent;
}
知道原因后就好办了,让我手动跳转吧
rewrite ^/([0-9a-z]+)job$ /$1job/permanent;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2last;
示例17:域名跳转
server
{
listen 80;
server_name jump.linuxidc.com;
index index.html index.htm index.php;
root /opt/lampp/htdocs/www;
rewrite ^/ http://www.linuxidc.com/;
access_log off;
}
示例18:多级域名跳转
server_name www.linuxidc.comwww.linuxidc.net;
index index.html index.htm index.php;
root /opt/lampp/htdocs;
if ($host ~ "linuxidc\.net") {
rewrite ^(.*) http://www.linuxidc.com$1permanent;
}
示例19:
if ($slow) {
limit_rate 10k;
break;
}
限流. Nginx的http核心模块ngxhttpcoremodule中提供limitrate这个指令可以用于控制速度,limitrateafter用于设置http请求传输多少字节后开始限速。
示例20:
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;
}
示例21:
if ( $query_string ~* ".*[;'<>].*" ) {
return 404;
}
通过判断 URI 中是否有 ’、;、>、< 等字符可以快速过滤掉可能发生 SQL 注入的请求,然后直接返回 404 Not Found,可用于防sql注入。
示例22:
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /app.php break;
}
}
将不存在的请求定义到 app.php 处理
注意:在server中使用rewrite ,我们使用的flag是last,但是在location中,我们却只能用break,这是因为如果在location的rewrite也使用last,便会再次以新的URI重新发起内部重定向,再次进行location匹配,而新的URI中极有可能和旧的URI一样再次匹配到相同location中,这样死循环发生了。当循环到第10次时,Nginx会终止这样无意义的循环,并返回500错误。