nginx的rewrite用法及常用rewrite讲解

一、nginx的rewrite的用法

rewrite 匹配模式 替换模式 [flag];
如:

  1. rewrite ^(.*)$ /index.php$1 last;
  • 上例中 ^(.*)$ 为匹配模式
  • /index.php$1为替换表达式
  • last为修饰符flag

修饰符共有以下几种:

  • last:表示当前的重写规则是最后的应用。在这条规则之后的新的URI被nginx处理并且查找一个location区段,后面的rewrite指令将被忽略。
  • break:当前的重写规则被应用后,对于替换的URI不再重新搜索,后面的rewrite指令也将被忽略
  • redirect:返回 302重定向,并且通过一个替代的URI作为location的头

二、rewrite中条件结构

一般用在判断条件if中

用法: if (变量 操作符 匹配模式或值)

如:if ($request_method == POST)

操作符共有以下几种:

无操作符:如果指定的变量不为空或者不为0的字符串,则条件为真

如: if ($string) {}

  • =或!=:表示变量等于(当操作符为=时)某个值或者变量不等于(!=)某个值时条件为真

  • ~或!~:当变量匹配(~)或不匹配(!~)变个模式时条件为真(区分大小写)

  • ~或!~:当变量匹配(~)或不匹配(!~)变个模式时条件为真(不区分大小写)

  • -f 或!-f:表示文件存在(-f)或者文件不存在(!-f)

  • -d或者!-d表示目录存在或者不存在

  • -e或者!-e表示文件或目录存在或者不存在

  • -x或!-x:表示文件是否存在并且可执行

注:if 后面一定要有空格

三、rewrite中的指令

1、break:阻止后面的rewite指令
2、return:中断请求,并且返回 一个HTTP状态码

如:return 403;

3、set:初始化或设置一个变量
四、rewrite的实例
1、实现wordpress伪静态重写(各PHP框架隐藏index.php入口文件也是这种)

wordpress的文章默认的URL形式是:http://website.com/?p=11

其实都是通过入口文件index.php来对URL进行解析分发的,其他的路径都是通过wordpress的URL路由实现解析的

进入wordpress后台我们可以看到有几种可以使用的URL形式,其实都是隐藏了index.php

只需要在nginx.conf中隐藏其index.php即可。

  1. location /wordpress/ {
  2. if (!-e $request_filename) {
  3. rewrite ^/wordpress/(.*)$ /wordpress/index.php/$1 last;
  4. }
  5. }

如果你使用的是域名,而且域名指定的根目录就是wordpress,那么你可以使用下面的配置

  1. location / {
  2. if(!-e $request_filename)
  3. {
  4. rewrite ^(.*)$ /index.php$1 last;
  5. }
  6. }
2、实现ecshop的伪静态
(1)产品分类页

产品分类是ecshop重写最复杂的部分,因为参数比较多,我就拿最复杂的那个地址来重写,其他的简单的可以参照这个

原地址:category.php?id=3&brand=0&price_min=0&price_max=0&filter_attr=0.0.160.186

重写后的地址:category-3-b0-min0-max0-attr0.0.160.186-GSM%E6%89%8B%E6%9C%BA.html

最后面的那个参数0.0.160.186其实是四个属性的值,分别是颜色、屏幕大小、手机制式、手机外观样式(当然我们不需要知道这些)

分析:重写后的category后面的3是分类ID,b后面是品牌ID,min后面是价格起始值,max是价格最大值,attr后面是属性值

  1. rewrite ^(.*)/category-(d+)-b(d+)-min(d+)-max(d+)-attr((d+.)+d+)-(.*).html$ $1/category.php?id=$2&brand=$3&price_min=$4&price_max=$5&filter_attr=$6 last;
(2)产品详细页

原地址:goods.php?id=17

重写后地址:goods-17-夏新N7.html

分析:重写的地址17代表产品ID,夏新N7代表产品名称

因此重写规则为:

  1. rewrite ^(.*)/goods-(d+)-(.*).html $1/goods.php?id=$2 last;
(3)文章分类

原地址:article_cat.php?id=5

重写后的地址:article_cat-5-新手上路+.html

分析:重写后的5代表分类ID,新手上路+这几个字代表分类的标题

因此重写规则为:

  1. rewrite ^(.*)/article_cat-(d+)-(.*).html$ $1/article_cat.php?id=$2 last;
(4)文章详细页

原地址:article.php?id=9

重写后的地址:article-9-售后流程.html

分析:那个重写后的数字9即为文章的ID,今后流程为文章的标题

所以重写规则为:

  1. rewrite ^(.*)/article-(d+)-(.*).html$ $1/article.php?id=$2 last;
(5)品牌列表页

原地址:brand.php?id=1

重写后的地址:brand-1-c0-诺基亚.html

分析:那重写后的那个1代表的是品牌的Id,c后面的0代表是品牌下的分类,那个诺基亚就是品牌的名称了(产品品牌的ID肯定是数字,分类ID也是数字)

所以重写规则为:

  1. rewrite ^(.*)/brand-(d+)-c(d+)-(.*).html$ $1/brand.php?id=$2&cat=$3 last;
(6)标签列表页

原地址:search.php?keywords=音乐手机(即search.php?keywords=标签名)

重写后的地址:tag-音乐手机.html (即tag-标签名.html)

这个音乐手机是中文,是否可以用w来匹配呢?(我开始的想法也是用w来匹配,但实际上不可以,w表示英文字母、数字或下划线,所以这个标签名只能通过.来匹配),因此:

最后的重写规则为:

  1. rewrite ^(.*)/tag-(.*).html $1/search.php?keywords=$2
  • 第一个括号中(.*)代表/tag前的部分,可能是域名,也可能是域名+目录

  • 第二个括号中(.*)代表标签名

注:$1和$2是反向引用,$1表示第一个括号匹配的内容,$2表示第二个括号匹配的内容

3、实现thinkphp的URL的PATHINFO这种模式:
(1)第一步实现pathinfo模式

我们分析一下pathinfo模式的规则:

如:

http://localhost/thinkphp/index.php/news/index这种,那么我们可以把这段分为两部分

  • 第一段

http://localhost/thinkphp/index.php,这是真实文件的地址

  • 第二段

news/index是key/value形式的参数、

因此,我们可以通过正则表达式来分隔它们: ^(.+.php)

  1. location ~* ^(.+.php)(.*)$ {
  2. root /webdata/www/;
  3. fastcgi_pass 127.0.0.1:9000;
  4. fastcgi_index index.php;
  5. fastcgi_split_path_info ^(.+.php)(.*)$;
  6. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  7. fastcgi_param PATH_INFO $fastcgi_path_info;
  8. include fastcgi_params;
  9. }
(2)隐藏index.php
  1. location / {
  2. if (!-e $request_filename)
  3. {
  4. rewrite ^(.*)$ /index.php$1 last;
  5. }
  6. }

原理:如果URL请求的文件不存在,则在这个地址前面加上index.php再重新匹配

  • !-e是一个表达式,表示文件不存在,类似的还有:

  • !-f表示是一个文件不存在

  • !-d表示一个目录不存在

  • $request_filename是nginx的变量,表示请求的文件,更多的nginx变量请查看 nginx模块核心变量

  • 正则表达式部分^(.*)$可以匹配所有URL ,$1表示分组1匹配的结果即()匹配的结果

  • last表示本次匹配结束