概述

本文主要针对nginx rewrite指令困惑的地方进行讲解,中间会涉及部分原理部分,我尽量用通俗易懂的语言来形容

功能讲解

大致流程

The ngx_http_rewrite_module module directives are processed in the following order:

the directives of this module specified on the server level are executed sequentially;

repeatedly:

  • a location is searched based on a request URI;

  • the directives of this module specified inside the found location are executed sequentially;

  • the loop is repeated if a request URI was rewritten, but not more than 10 times.

涉及phase
  • NGX_HTTP_SERVER_REWRITE_PHASE,

  • NGX_HTTP_FIND_CONFIG_PHASE,

  • NGX_HTTP_REWRITE_PHASE,

  • NGX_HTTP_POST_REWRITE_PHASE,

环境:
  • /aaa内容aaa

  • /bbb内容bbb

Example 1:
server {
    listen   80;
    location /aaa {
    if ($http_user_agent ~ Mozilla) {
            rewrite /aaa /bbb; 
    }
    return 403;
    }
    location /bbb {
    return 402
    }
}

在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

然后继续执行rewrite模块其他指令,执行到return 403后,该request在nginx中的处理完毕,返回403;

因此浏览器收到应答码为403

Example 2:
    server {
        listen   80;
        location /aaa {
        if ($http_user_agent ~ Mozilla) {
                rewrite /aaa /bbb; 
        }
#        return 403;
        }
        location /bbb {
        return 402
        }
    }

在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb)

rewrite模块执行完毕。因为所有rewrite模块的指令都执行完毕,进入POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase

中,由于执行了rewrite指令,在函数ngx_http_script_regex_start_code中

if (code->uri) {
    r->internal = 1;
    r->valid_unparsed_uri = 0;
    if (code->break_cycle) {//rewrite ....break 指令分支
        r->valid_location = 0;
        r->uri_changed = 0;
    else {
        r->uri_changed = 1;
    }
}

可以得知r->uri_changed=1,于是在函数ngx_http_core_post_rewrite_phase中执行如下流程

r->uri_changes--;
if (r->uri_changes == 0) {
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "rewrite or internal redirection cycle "
                  "while processing \"%V\"", &r->uri);
    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
    return NGX_OK;
}
r->phase_handler = ph->next;//ph->next为find_config_index,在ngx_http_init_phase_handlers中可见
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->loc_conf = cscf->ctx->loc_conf;

由于重新进行server和location匹配,因此在上述例子中,浏览器收到的应答状态吗为402

Example 3:
server {
    listen   80;
    location /aaa {
    if ($http_user_agent ~ Mozilla) {
            rewrite /aaa /bbb break
    }
    return 403;
    }
    location /bbb {
        return 402
    }
}

在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

由于rewrite break标记符存在,从rewrite指令的配置解析函数ngx_http_rewrite和rewrite模块的handler函数ngx_http_rewrite_handler中

如下部分可以得知,将停止执行rewrite模块的其他一切指令;

ngx_http_rewrite {
....
....
    if (cf->args->nelts == 4) {
        if (ngx_strcmp(value[3].data, "last") == 0) {
            last = 1;
        else if (ngx_strcmp(value[3].data, "break") == 0) {
            regex->break_cycle = 1;
            last = 1;
        else if (ngx_strcmp(value[3].data, "redirect") == 0) {
            regex->status = NGX_HTTP_MOVED_TEMPORARILY;
            regex->redirect = 1;
            last = 1;
        else if (ngx_strcmp(value[3].data, "permanent") == 0) {
            regex->status = NGX_HTTP_MOVED_PERMANENTLY;
            regex->redirect = 1;
            last = 1;
        else {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid parameter \"%V\"", &value[3]);
            return NGX_CONF_ERROR;
        }
.....
.....
.....
    if (last) {
        code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
        if (code == NULL) {
            return NGX_CONF_ERROR;
        }
        *code = NULL;
    }
}
ngx_http_rewrite_handler
{
.....
.....
    while (*(uintptr_t *) e->ip) {
        code = *(ngx_http_script_code_pt *) e->ip;
        code(e);
    }
    if (e->status < NGX_HTTP_BAD_REQUEST) {//如果rewrite指令后不是break和last标记,而是其他两个重定向标记,则从此处直接结束该request处理流程
        return e->status;
    }
    if (r->err_status == 0) {
        return e->status;
    }
    return r->err_status;
.....
.....
}

进入到POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2 可知r->uri_changed = 0;

在ngx_http_core_post_rewrite_phase中会执行如下流程,因此会继续执行当前server 和 location 上下文中后续的handler,因此浏览器收到内容为bbb

if (!r->uri_changed) {
    r->phase_handler++;
    return NGX_AGAIN;
}
Example 4:
server {
    listen   80;
    location /aaa {
    if ($http_user_agent ~ Mozilla) {
            rewrite /aaa /bbb last; 
    }
    return 403;
    }
    location /bbb {
        return 402
    }
}

在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),

由于rewrite last标记符存在,停止执行rewrite模块的其他一切指令,参考example 3。

进入到rewrite模块所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2可知r->uri_changed = 1;

于是重新进行server和location匹配,因此在上述例子中,浏览器收到的内容的状态码为402

转载于:https://www.cnblogs.com/scottieyuyang/p/5722604.html

Nginx “邪恶” rewrite相关推荐

  1. Nginx的rewrite应用

    Rewrite主要的功能是实现URL重写,Nginx 的 Rewrite 规则采用 PCRE Perl 兼容正则表达式的语法进行规则匹配,如相使用 Nginx 的 Rewrite 功能,在编译 Ngi ...

  2. index.php?s=$1,thinkphp nginx配置rewrite,地址会多出个.php

    thinkphp nginx配置rewrite,地址会多出个.php ,http://localhost:7080/.php?m=... nginx配置文件 server { listen 80; # ...

  3. php ci nginx 伪静态rewrite配置方法

    php ci nginx 伪静态rewrite配置方法 location / {if (!-e $request_filename) {rewrite ^(.*)$ /index.php?s=/$1 ...

  4. nginx的rewrite 参数和例子

    nginx的rewrite 参数和例子 正则表达式匹配,其中: * ~ 为区分大小写匹配 * ~* 为不区分大小写匹配 * !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配,其中 ...

  5. 第七章:nginx的rewrite规则详解

    模块ngx_http_rewrite_module 该ngx_http_rewrite_module模块用于使用PCRE正则表达式更改请求URI,返回重定向,并有条件地选择配置. 句法: break; ...

  6. Nginx之rewrite配置

    Rewtrite : 其主要目的是为了进行URL 重写,进行URL重定向.主要采用PCRE: Perl Compatible Regular Expressions(Perl兼容正则表达式语法)进行规 ...

  7. php选择nginx还是apache,浅谈apache和nginx的rewrite的区别

    1. Nginx Rewrite规则相关指令 Nginx Rewrite规则相关指令有if.rewrite.set.return.break等,其中rewrite是最关键的指令.一个简单的Nginx ...

  8. Nginx的rewrite模块疑问排查

    标题索引 追溯原因 实验分析 原理总结 追踪原因 最近心态"一步一印,有印为证",在Nginx的rewrite模块在工作过程中,客户端发起包到服务器解包整体过程浏览器做了什么?服务 ...

  9. 实例演示Nginx重写(Rewrite)类型last、break、redirect和permanent的区别

    本文使用之前制作的Docker容器<<Docker案例:搭建nginx服务>>演示Nginx四种重写类型的区别和效果,如果尚未构建Docker服务可参考之前的文章,或者自建Ng ...

最新文章

  1. python分治算法_python算法实现-分治法
  2. 2018-11-02 在代码中进行中文命名实践的短期目标
  3. Struts2之文件下载
  4. python子进程进行kinit认证_使用kafka-python客户端进行kafka kerberos认证
  5. (62)FPGA一维数组(reg)
  6. HDU 3082 HDOJ 3082 Simplify The Circuit ACM 3082 IN HDU
  7. HTML5期末大作业:直播网站设计——仿在线媒体歪秀直播官网模板html源码(11个页面) HTML+CSS+JavaScript 期末作业HTML代码...
  8. 毕业生 - 哈尔滨工业大学社会计算与信息检索研究中心 - 理解语言,认知社会...
  9. 高等数学-函数在线绘图工具推荐(精选好用)
  10. Word文档字间距怎么调?
  11. 笔记本计算机摄像头怎么打开,手把手教你笔记本内置摄像头打不开解决方法
  12. 04-Groovy-运算符
  13. [含lw+源码等]S2SH+mysql的报刊订阅系统[包运行成功]Java毕业设计计算机毕设
  14. Linux各个文件夹的作用
  15. matlab 矩阵 对称,如何使用Matlab产生对称矩阵
  16. JS实现当前日期是第几周
  17. 深入探究宽字节注入漏洞与修补原理
  18. 易基因项目文章 | 90天见刊,易基因m6A RNA甲基化(MeRIP)+转录组组学研究
  19. VB6 简单实现 支付宝二维码扫马支付
  20. 安卓UTC与时间日期互转方法

热门文章

  1. vasp服务器中断,求助VASP能带计算的中断原因 - 第一原理 - 小木虫 - 学术 科研 互动社区...
  2. 2021年 985 网络空间安全专业 保研路
  3. 【C51开发应用】基于C51单片机开发的循迹灭火机器人
  4. 山沟沟里的技术脱贫:阿里工程师助平武蜂农物联网养蜂...
  5. 2015十大CMS系统介绍
  6. YY视频直播体验优化实践
  7. 多少人败给了一个字:等……
  8. SQL高级语法学习总结(一)
  9. redis跟memcached有啥子区别
  10. Tomcat配置完成后打不开localhost网页解决方法