架构web服务-Nginx之八-nginx实现Rewrite重写

Rewrite

MarkdownHTML

08·Nginx实现Rewrite重写

  • 08·Nginx实现Rewrite重写
    • [Rewrite基本概述](file:///F:/老男孩72期脱产班笔记/第二阶段架构/rewrite-https/Rewrite.html#title-1)
    • [Rewrite标记Flag](file:///F:/老男孩72期脱产班笔记/第二阶段架构/rewrite-https/Rewrite.html#title-2)
    • [Rewrite规则实践](file:///F:/老男孩72期脱产班笔记/第二阶段架构/rewrite-https/Rewrite.html#title-3)

Rewrite基本概述

什么是rewrite

Rewrite主要实现url地址重写,以及重定向,就是把传入web的请求重定向到其他url的过程。


Rewrite使用场景

1、地址跳转,用户访问www.lzy.com这个URL是,将其定向至一个新的域名mobile.lzy.com
2、协议跳转,用户通过http协议请求网站时,将其重新跳转至https协议方式
3、伪静态,将动态页面显示为静态页面方式的一种技术,便于搜索引擎的录入,同时建上动态URL地址对外暴露过多的参数,提升更高的安全性。
4、搜索引擎,SEO优化依赖于url路径,好记的url便于智齿搜索引擎录入


Rewrite配置示例

句法:Syntax:  rewrite regex replacement [flag]
默认:Default: --
语境:Context: server,location,if

#用于切换维护页面场景
#rewrite ^(.*)$ /page/maintain.html break;

Rewrite标记Flag

rewrite指令根据表达式来重定向URL,或者修改字符串,可以应用于server,location,if环境下,每行rewrite指令最后跟一个flag标记,支持的flag标记有如下表格所示:

flag 作用
last 本条规则匹配完成后,停止匹配,不再匹配后面的规则
break 本条规则匹配完成后,停止匹配,不再匹配后面的规则
redirect 返回302临时重定向,地址栏会显示跳转后的地址
permanent 返回301永久重定向,地址栏会显示跳转后的地址

last与break区别对比示例

[root@web01 ~]# cat > /etc/nginx/conf.d/rewrite.conf <<EOF 
server {
        listen 80;
        server_name rewrite.lzy.com;
        root /code;

        location ~ ^/break {
                rewrite ^/break /test/ break;
        }
        location ~ ^/last {
                rewrite ^/last /test/ last;
        }
        location /test/ {
                default_type application/json;
                return 200 "ok";
        }
}
EOF
#重启nginx服务
[root@web01 conf.d]# nginx -t 
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web01 conf.d]# nginx -s reload

如果懂shell脚本的,这两个就类似于脚本中的,breakcontinue


windows配置:在C:\Windows\System32\drivers\etc\hosts文件中修改一行10.0.0.7 rewrite.lzy.com

浏览器访问break

image-20200923191003808


浏览器访问last

image-20200923191306488


last与break区别

break 只要匹配到规则,则会去本地配置路径的目录中寻找请求的文件;
而last只要匹配到规则,会对其所在的server(…)标签重新发起请求。

break请求:
1、请求rewrite.lzy.com/break
2、首先:会去查找本地的/code/test/index.html;
3、如果找到了,则返回/code/test/index.html的内容;
4、如果没找到该目录则报错404,如果找到该目录没找到对应的文件则403

last请求:
1、请求rewrite.lzy.com/last
2、首先:会去查找本地的/code/test/index.html;
3、如果找到了,则返回/code/test/index.html的内容;
4、如果没找到,会对当前server重新的发起一次请求,rewrite.lzy.com/test/
5、如果有location匹配上,则直接返回该location的内容。
4、如果也没有location匹配,再返回404;

所以,在访问/break和/last请求时,虽然对应的请求目录/test都是不存在的,理论上都应该返回404,但是实际上请求/last的时候,是会有后面location所匹配到的结果返回的,原因在于此。


redirect与permanent区别对比示例

[root@web01 ~]# cat > /etc/nginx/conf.d/rewrite.conf <<EOF 
server {
        listen 80;
        server_name rewrite.lzy.com;
        root /code;

        location /test {
                rewrite ^(.*)$  http://www.oldboyedu.com redirect;
                #rewrite ^(.*)$  http://www.oldboyedu.com permanent;
                #return 301 http://www.oldboyedu.com;
                #return 302 http://www.oldboyedu.com;
        }
}
EOF

redirect与permanent区别)实现https

![img](file:///F:/%E8%80%81%E7%94%B7%E5%AD%A972%E6%9C%9F%E8%84%B1%E4%BA%A7%E7%8F%AD%E7%AC%94%E8%AE%B0/%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%9E%B6%E6%9E%84/rewrite-https/Rewrite_files/5e69f8402f92f45ddb000002.png)

![img](file:///F:/%E8%80%81%E7%94%B7%E5%AD%A972%E6%9C%9F%E8%84%B1%E4%BA%A7%E7%8F%AD%E7%AC%94%E8%AE%B0/%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%9E%B6%E6%9E%84/rewrite-https/Rewrite_files/5e69f8c82f92f45ddb000003.png)

redirect: 每次请求都会询问服务器,如果当服务器不可用时,则会跳转失败。

permanent: 第一次请求会询问,浏览器会记录跳转的地址,第二次则不再询问服务器,直接通过浏览器缓存的地址跳转。

Rewrite规则实践

在写rewrite规则之前,我们需要开启rewrite日志对规则的匹配进行调试。

[root@web01 ~]# vim /etc/nginx/nginx.conf
/var/log/nginx/error.log notice;

http{
    rewrite_log on;
}

案例一

用户访问/abc/1.html实际上真实访问的是/ccc/bbb/2.html

#http://www.lzy.com/abc/1.html  ==>  http://www.lzy.com/ccc/bbb/2.html

#1.准备真实访问路径
[root@web01 ~]# mkdir /code/ccc/bbb -p
[root@web01 ~]# echo "ccc_bbb_2" > /code/ccc/bbb/2.html

#2.Nginx跳转配置
[root@web01 ~]# cat > /etc/nginx/conf.d/ccbb.conf <<EOF 
server {
        listen 80;
server_name www.lzy.com;
        location / {
                root /code;
                index index.html;
        }
        location /abc {
                rewrite (.*) /ccc/bbb/2.html redirect;
                #return 302 /ccc/bbb/2.html;   跳转所以/abc目录根本不管用     /code/ccc/bbb/2.html
        }
}
EOF



#3.重启Nginx服务
[root@web01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web01 conf.d]# nginx -s reload

image-20200923205254876

windows配置:在C:\Windows\System32\drivers\etc\hosts文件中修改一行10.0.0.7 www.lzy.com

案例二

用户访问/2018/ccc/2.html实际上真实访问的是/2014/ccc/bbb/2.html

##http://www.lzy.com/2018/ccc/2.html  ==>  http://www.lzy.com/2014/ccc/bbb/2.html

#1.准备真实的访问路径
[root@web01 ~]# mkdir /code/2014/ccc/bbb -p 
#2.Nginx跳转配置
[root@web01 ~]# cat > /etc/nginx/conf.d/ccbb.conf <<EOF
server {
        listen 80;
server_name www.lzy.com;
        location / {
                root /code;
                index index.html;
        }
        location /2018 {
                rewrite ^/2018/(.*)$ /2014/\$1 redirect;
        }
}
EOF
#www.lzy.com/2018/ccc/index.html---->/2014/ccc/index.html  redirect;
#3.重启nginx服务
[root@web01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web01 conf.d]# nginx -s reload
[root@web01 ~]# echo aaaaa > /code/2014/ccc/index.html

image-20200923210701137

案例三

用户访问/test实际上真实访问的是https://www.oldboy.com

#1.Nginx跳转配置
[root@web01 conf.d]# cat > /etc/nginx/conf.d/test.conf <<EOF
server {
        listen 80;
server_name www.lzy.com;
        location /test {
                rewrite (.*) https://www.baidu.com redirect;
        }
}
EOF
#2.重启nginx服务
[root@web01 conf.d]# nginx -s reload

案例四

用户访问course-11-22-33.html实际上真实访问的是/course/11/22/33/course_33.html

#http://www.lzy.com/couese-11-22-33.html  ==>  http://www.lzy.com/course/11/22/33/course_33.html

#1.准备真实的访问路径
[root@web01 ~]# mkdir /code/course/11/22/33 -p
[root@web01 ~]# echo "curl docs.etiantian.org" > /code/course/11/22/33/course_33.html

#2.Nginx跳转配置
[root@web01 conf.d]# cat test.conf 
server {
        listen 80;
server_name www.lzy.com;
root /code;
        index index.html;
        location / {
                #灵活配法
                rewrite ^/course-(.*)-(.*)-(.*).html$ /course/$1/$2/$3/course_$3.html redirect;
                #固定配法
                #rewrite ^/course-(.*) /course/11/22/33/course_33.html redirect;
        }
}

#3.重启nginx服务
[root@web01 conf.d]# nginx -s reload

案例五

http请求跳转到https

#Nginx跳转配置
[root@web01 ~]#cat > /etc/nginx/conf.d/www.conf <<EOF
server {
        listen 80;
        server_name www.oldboy.com;
        rewrite ^(.*) https://\$server_name$1 redirect;
        #return 302 https://\$server_name$ request_uri;
}       

server {
        listen 443;
        server_name www.oldboy.com;
        ssl on;
}
EOF

Rewrite伪静态

伪静态就是将动态网页做url重写操作(即rewrite)处理成静态页面。

  • www.kevin.com/jk/fd.php?=12 ==> www.kevin.com/jk-fd-12.html
  • 动态页面:如.php、.asp、.aspx等格式,有时后跟"?"加参数来读取数据库内不同资料

伪静态是一种可以把文件后缀改成任何可能的一种方法,比如把php文件伪静态成html文件。

  1. 从URL结构以及页面名称看,伪静态和静态页面是一样的。伪静态的页面后缀可以是html或者htm或者是目录格式
  2. 伪静态只是改变了URL的表现形式,实际上还是动态页面
  3. 静态页面可以节省服务器资源,而伪静态严格说是增加服务器资源消耗的

WordPress的伪静态规则:

  1. 在WordPress程序后台 - 设置 - 固定链接设置
  2. 修改Nginx配置,添加如下location / {...}
location / {
     # Nginx会检查$uri是否存在文件,然后检查目录$uri/。如果找不到目录或文件,
     # 它将执行内部重定向以/index.php将查询字符串参数作为参数传递。
     try_files $uri $uri/ /index.php?$args;
}

Nginx相关文章资料库:WordPress的永久链接

WordPress固定链接小提示:

  • 固定链接最好是在建站时就定好;
  • 如果后期变更固定链接一定要做好301跳转,可以搜索选择Redirection插件来解决;
  • 固定链接本身并不能达到很科学的SEO效果,各种方式并无区别;
  • 不要纠结固定链接是个什么样子。

Nginx配置WordPress官方示例(二级目录下):

server {
    listen 80;
    server_name blog.oldboy.com;
    root /code/wordpress;
    index index.php index.html;
    client_max_body_size 100m;

    location ~ \.php$ {
        root /code/wordpress;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param  HTTPS on;
        include        fastcgi_params;
    }
    
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
 
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }
 
    location / {
         try_files $uri $uri/ /index.php?$args;
     }
 
     location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
         expires max;
         log_not_found off;
     }
}

WordPress官方资料

Rewrite规则参考资料

正则表达式匹配:
~      为区分大小写的匹配
~*     不区分大小写的匹配(匹配firefox的正则同时匹配FireFox)
!~     区分大小写的不匹配
!~*    不区分大小写的不匹配

.      匹配除换行符以外的任意字符
\w     匹配字母或数字或下划线或汉字
\s     匹配任意的空白符
\d     匹配数字
\b     匹配单词的开始或结束
^      匹配字符串的开始
$      匹配字符串的结束

*      重复零次或更多次
+      重复一次或更多次
?      重复零次或一次
{n}    重复n次
{n,}   重复n次或更多次
{n,m}  重复n到m次
*?     重复任意次,但尽可能少重复
+?     重复1次或更多次,但尽可能少重复
??     重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}?  重复n次以上,但尽可能少重复

\W     匹配任意不是字母,数字,下划线,汉字的字符
\S     匹配任意不是空白符的字符
\D     匹配任意非数字的字符
\B     匹配不是单词开头或结束的位置
[^x]   匹配除了x以外的任意字符

文件及目录匹配判断:
-f和!-f   用来判断是否存在文件
-d和!-d   用来判断是否存在目录
-e和!-e   用来判断是否存在文件或目录
-x和!-x   用来判断文件是否可执行

$args             此变量与请求行中的参数相等
$content_length   等于请求行的“Content_Length”的值。
$content_type     等同与请求头部的”Content_Type”的值
$document_root    等同于当前请求的root指令指定的值
$document_uri     与 $uri 一样
$host             与请求头部中“Host”行指定的值或是request到达的server的名字(没有Host行)一样
$http_user_agent
$http_cookie
$limit_rate       允许限制的连接速率
$remote_addr      客户端ip
$remote_port      客户端port
$remote_user      等同于用户名,由ngx_http_auth_basic_module认证
$request_filename  当前请求的文件的路径名,由root或alias和URI请求组合而成
$request_body_file
$request_uri      含有参数的完整的初始URI
$request_method   等同于request的method,通常是“GET”或“POST”
$query_string     与 $args一样
$scheme           用的协议,比如http或者https
$server_protocol  等同于request的协议,使用“HTTP/1.0”或“HTTP/1.1”
$server_addr      请求的服务器ip,一般获得此变量的值的目的是进行系统调用。为了避免系统调用,有必要在listen指令中指明ip,并使用bind参数。
$server_name      请求的服务器域名
$server_port      请求的服务器端口号
$uri              等同于当前request中的URI,可不同于初始值,例如内部重定向时或使用index

Rewrite常用示例

http协议转https协议

server {
        listen 80;
        server_name test.linux.com;
        root /code;
        return 302 https://$server_name$request_uri;
}

多目录转成参数

abc.domian.com/sort/2 ==> abc.domian.com/index.php?act=sort&name=abc&id=2

if ($host ~* (.*)/.domain/.com) {
    set $sub_name $1;
    rewrite ^/sort//(/d+)//?$ /index.php?act=sort&cid=$sub_name&id=$1 last;
}

目录对换

/123456/xxxx -> /xxxx?id=123456

rewrite ^/(/d+)/(.+)/ /$2?id=$1 last;

用户用ie访问时重定向到/nginx-ie目录:

if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /nginx-ie/$1 break;
}

目录自动加“/”

if (-d $request_filename){
    rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}

禁止.htaccess

location ~//.ht {
    deny all;
}

禁止多个目录

location ~ ^/(cron|templates)/ {
    deny all;
    break;
}

禁止以/data开头的文件

可以禁止/data/下多级目录的请求;

location ~ ^/data {
    deny all;
}

禁止单个目录

location /data/ {
    deny all;
}

禁止单个文件

location ~ /data/sql/data.sql {
    deny all;
}

设定某个文件的过期时间

99天,不记录404错误日志

location ~(favicon.ico) {
    log_not_found off;
    expires 99d;
    break;
}

600秒,不记录访问日志

location ^~ /html/scripts/loadhead_1.js {
    access_log off;
    root /opt/lampp/htdocs/web;
    expires 600;
    break;
}

文件反盗链并设置过期时间

location ~* ^.+/.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
    valid_referers none blocked *.jb51.net *.jbzj.net localhost 1.1.1.1;
    if ($invalid_referer) {
        rewrite ^/ http://www.jb51.net/jb51.gif; # 显示一张防盗链图片
        return 412;              # 自定义http状态码412,默认为403
        break;
    }
    access_log off;
    root /opt/lampp/htdocs/web;
    expires 3d;                  # 所有文件3天的浏览器缓存
    break;
}

将多级目录下的文件转成一个文件,增强seo效果

/job-123-456-789.html ==> /job/123/456/789.html

rewrite ^/job-(0-9+)-(0-9+)-(0-9+)/.html$ /job/$1/$2/jobshow_$3.html last;

文件或目录不存在的时候重定向:

if (!-e $request_filename) {
    proxy_pass http://127.0.0.1;
}

域名跳转

rewrite ^/ http://www.jb51.net/;

多域名转向

if ($host ~ “c1gstudio/.net”) {
    rewrite ^(.*) http://www.jb51.net$1 permanent;
}

三级域名跳转

if ($http_host ~* “^(.*)/.i/.c1gstudio/.com$”) {
    rewrite ^(.*) http://www.jb51.net$1;
    break;
}

域名镜像

rewrite ^/(.*) http://www.jb51.net/$1 last;

某个子目录作镜像

location ^~ /php {
    rewrite ^.+ http://www.jb51.net/ last;
    break;
}

Rewrite匹配优先级

  1. 先执行server层的rewrite
  2. 再根据location匹配优先级匹配
  3. 再执行location下的rewrite
  4. 最后再执行location下if配置的rewrite

配置测试:

[root@web01 ~]# vi /etc/nginx/conf.d/priority.conf
server {
    listen 80;
    server_name linux.youxian.com;
    location / {
        rewrite (.*) http://www.jd.com;
    }

    location =/ {
        rewrite (.*) http://www.taobao.com;
    }

    rewrite (.*) http://www.baidu.com;
}

Rewrite推荐书写格式

旧配置方法

server {
        listen 80;
        server_name www.baidu.com baidu.com;
        if ($http_host = baidu.com){
            rewrite (.*) http://www.baidu.com$1;
        }
}



新配置方法

server {
        listen 80;
        server_name baidu.com;
        return 302 http://www.baidu.com$request_uri;
}
server {
        listen 80;
        server_name www.baidu.com;
}

推荐书写格式

server {
        listen 80;
        server_name baidu.com;
        include /etc/nginx/rewrite.conf;
}
server {
        listen 80;
        server_name www.baidu.com;
}

[root@lb01 ~]# cat > /etc/nginx/rewrite.conf <<EOF
return 302 http://www.baidu.com$request_uri;
#rewrite ^(.*)$ http://www.baidu.com redirect;
EOF
posted @ 2021-03-06 23:17  上善若水~小辉  阅读(307)  评论(0编辑  收藏  举报