美文网首页Nginx 服务器Nginx高端成长之路
Nginx的HttpRewrite模块在多站点静态页场景的妙用

Nginx的HttpRewrite模块在多站点静态页场景的妙用

作者: 9c46ece5b7bd | 来源:发表于2019-03-02 17:37 被阅读1次

从多站点静态页来看Nginx的HttpRewrite模块

背景:

在工作中我们通常会使用Nginx来部署静态页,不仅因为Nginx强大的web服务器功能,供重要的是因为Nginx可以充当静态页缓存服务,可以大大加速用户访问速度,提高用户体验。

但是通常服务器上仅用Nginx部署单站点静态页会造成资源的极大浪费(主机,网络资源等),因此企业内部经常会使用单独的区域,单独的主机来构建一个Nginx集群来专门用作企业内部的公共静态服务。这个时候我们就会将不同站点的静态内容都部署到该集群,而此时可能遇到的问题就会是可能多个站点会有相同的URI,但是希望定位到的是不同站点的资源,此时就需要借助HttpRewrite模块中的一些指令来完成。

例如: www.bgops.com 站点希望访问的资源A,而test-1.bgops.comtest-2.bgops.com站点希望访问的是资源B,对应而后的URI也是相应的(比如每个站点都会有domain/URI 资源)

如上场景,我们第一时间想到的会是通过headerhost来判断站点,从而定位到响应资源,比如:

location / {
    if ($host = 'www.bgops.com') {
        root /var/www/html/A;
    }
    if ($host ~* 'test-(\d+).bgops.com') {
        root /var/www/html/B;
    }
}

注意:if指令是不可以进行或与非判断的,因此需要借助set指令

如上场景其实可以满足我们的需求的,但是如果站点过多,而且匹配的URI较多,那么我们需要再每个location指令中进行很多的if指令的判断,这样可能会导致配置冗长,很难进行管理,要知道,作为运维大多数的事故都是源自于变更,而通常变更出事故的原因也大多数是因为配置冗长,不便于管理二导致配置误变更的。因此,我们需要熟悉nginx的执行阶段,以及相关的指令优化。

接下来从Nginx的主要执行阶段以及HttpRewrite模块来优化下我们上述的场景。

nginx的主要执行阶段以及执行顺序

nginx主要执行阶段

nginx标准模块之rewrite模块

注意: Nginx处理请求共可以划分11个阶段,主要为rewrite 、access 、content三个阶段.

  • rewrite:

    • ngx_rewrite模块。set、rewrite、return、brek、if指定
    • ngx_lua模块。set_by_lua指令
  • access:

    • ngx_access模块。deny、alllow指令(按照书写先后匹配)
    • ngx_lua模块。access_by_lua指令(access阶段末尾执行)
  • content:
    • ngx_echo模块。echo指令
    • ngx_lua模块。content_by_lua指令
    • ngx_proxy模块。proxy_pass指令

三个阶段的执行顺序遵循以下基本规则:

    1. 执行顺序rewrite > access > content
    1. 同一阶段中的相同模块中的指令执行顺序是按照书写顺序匹配(比如access阶段的ngx_access模块中的deny和allow指令)
    1. 同一阶段中不同模块的指令执行顺序是不确定的(有的是顺序执行,有的依赖模块)

if和set指令的相关使用

首先,我们来看下if和set指令是在哪个模块以及作用域下.

从Nginx官方文档我们知道if和set指令均属于HttpRewrite模块,该模块主要用来允许使用正则表达式改变URI,并且根据变量来转向以及选择配置。

需要注意的是:在location内部的重写规则如果重复匹配的话会循环10次,之后Nginx会返回500错误

HttpRewrite模块相关指令

break指令

# 语法:break 
# 默认值:None
# 作用域: server,location,if
# 作用: 完成当前的规则匹配列
# 示例
if ($slow) {
    limit_rate 10k;
    break;
}

if指令

# 语法:if(condition) {}
# 默认值: None
# 作用域: server,location 
# 作用: 检测条件是否为真,并执行相关内容块定义的规则.
# 可以是如下条件:
## 变量名(使用默认变量或set指令自定义变量),假值会是一个空字符串""或者一个以"0"开始的任意字符串
## 变量和等号的比较(=或者!=)
## 正则匹配(~*和~,前者大小写敏感)
## 文件目录检测(-f and !-f 以及-d and !-d)
## 文件/目录/软链检测(-e and !-e)
## 可执行文件检测(-x)

# 示例
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;
}
## invalid_referers变量是valid_referers指令内置的变量
if ($invalid_referer) {
    return 403;
}

    

return指令

# 语法: return code
# 默认值: none
# 作用域: server,location,if
# 作用: 根据规则返回状态码

rewrite指令

# 语法: rewrite regex replacement flag
# 默认: none
# 作用域: server,location,if
# 作用: 根据表达式更改URI或修改字符串,指令根据配置文件顺序执行。

## 注意:重写仅对相对路径有效,如果想匹配主机名,需要使用if语句

# 示例
if ($host ~* www\.(.*)) {
    #$1 会匹配www.之后的域名
    set $host_without_www $1;
    #$1 为匹配到的相对URI 比如/bgops/abc
    rewrite ^(.*)$ http://$host_without_www$1 permanent;
}
## 注意:如果rewrite的内容是http://开始,客户端重定向之后其他的rewrite指令将不会执行(终止了)
## 不过可以使用参数来改变这一行为:
### last:完成rewrite指令的处理,然后搜索相应的URI和location
### break:完成rewrite指令的处理后结束
### redirect:返回临时重定向302,如果是http开头的比较有用
### permanent:返回永久重定向301

# 特殊字符的重定向
# 示例:
/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
# 默认值: none
# 作用域: server,location,if 
# 作用: 通常用来自定义变量,在if 中进行条件判断。其中value可以是一个变量,文本,以及变量和文本的集合

再来看我们上述的场景

我们可以借助setif指令来解决上述场景:

# nginx核心配置
    server {
        listen 80;
        server_name www.bgops.com  test1.bgops.com test2.bgops.com test3.bgops.com;

        root html;
        if ($host ~* "test(\d+).bgops.com") {
            set $servername 'testfamily';
        }
        location /  {

                root /export/Data/bgops;
                if ($servername ~* "testfamily") {
                    root /export/servers/nginx/html/i;
                }


                client_max_body_size       300m;
                client_body_buffer_size    128k;
        }
    
       location /statics {
           root /export/Data/bgops;
           if ($servername ~* "testfamily") {
                    root /export/servers/nginx/html/i;
                }
       }

   }
   

bash-4.1# cat /export/servers/nginx/html/i/index.html
iiiiiiiiiiii

bash-4.1# cat /export/servers/nginx/html/index.html
blog.bgops.com
bash-4.1# cat /export/Data/bgops/index.html
www.bgops.com

bash-4.1# curl localhost
blog.bgops.com
bash-4.1# curl -H 'host:www.bgops.com' localhost
www.bgops.com
bash-4.1# curl -H 'host:test1.bgops.com' localhost
iiiiiiiiiiii
bash-4.1# curl -H 'host:test2.bgops.com' localhost
iiiiiiiiiiii
bash-4.1# curl -H 'host:test3.bgops.com' localhost
iiiiiiiiiiii

相关文章

网友评论

    本文标题:Nginx的HttpRewrite模块在多站点静态页场景的妙用

    本文链接:https://www.haomeiwen.com/subject/vmkyuqtx.html