Nginx “邪恶” rewrite

概述

本文主要针对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:

    • 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

时间: 2024-12-29 06:57:06

Nginx “邪恶” rewrite的相关文章

nginx 配置rewrite 笔记

nginx 配置rewrite笔记: 通过下面的示例来说明一下,1. 先说说location : location 表示匹配传入的url地址,其中配置符有多种,各种情况的意义不一样: location ^~ /public/ { root /data/wwwroot/a.php.abc.cc; } location ^~ /public/ 表示匹配以 "/public/" 开头的url,匹配成功执行其中的内容,执行完毕后停止并退出. location / { root /data/ww

Nginx中 Rewrite学习笔记

路由重写是Web服务器中的一个很重要的基本功能.通过路由重写,可以结构化URL,更具语义化(对SEO有益).另外,分享出去的URL可能会因程序路由变动而导致URL失效,而路由的重写可以很好的解决这类问题. 适当的使用Rewrite功能,可以更我们带来很多的好处.Nginx中Rewrite的功能是基于perl语言兼容的正则表达式,所以在编译安装nginx之前,需要安装PREC库.Nginx中Rewrite功能实现是基于ngx_http_rewrite_module,所以确保安装了此模块. Rewr

Nginx的Rewrite规则与实例

通过Rewrite规则可以实现规范的URL.根据变量来做URL转向及选择配置,用好Rewrite有时起到事半功倍的效果. 语法 Nginx的Rewrite相比Apache的要好理解很多,主要使用指令有if.rewrite.set.return.break等,其中rewrite是最关键的指令. rewrite 语法: rewrite regex replacement [flag]; 默认值: — 上下文: server, location, if 如果指定的正则表达式能匹配URI,此URI将被r

nginx 配置rewrite

先说自己的情况,目前富乔使用的是lnmp一键包,解决步骤如下: 1.打开/usr/local/nginx/conf/nginx.conf   文件,在server段中,access_log句子前加入以下代码 location /ck/cashier/ { if (!-e $request_filename){ rewrite ^/ck/cashier/(.*)$ /ck/cashier/index.php?s=/$1 last; } } 其中/ck/cashier/  为二级目录,可根据自己的项

Nginx的Rewrite设置及示例

下面我介绍一下Nginx的Rewrite模块设置及Wordpress和Discuz的示例.Nginx的Rewrite规则比Apache的简单灵活多了,从下面介绍可见一斑. 首先,Nginx可以用if进行条件匹配,语法规则类似C,举例如下: if ($http_user_agent ~ MSIE) {rewrite  ^(.*)$  /msie/$1  break;}1.正则表达式匹配,其中: ~  为区分大小写匹配 ~* 为不区分大小写匹配 !~和!~*分别为区分大小写不匹配及不区分大小写不匹配

Nginx的rewrite应用

Rewrite主要的功能是实现URL重写,Nginx 的 Rewrite 规则采用 PCRE Perl 兼容正则表达式的语法进行规则匹配,如相使用 Nginx 的 Rewrite 功能,在编译 Nginx 前要编译安装 PCRE 库. 一,Nginx使用if进行条件匹配 Nginx可以用if进行条件匹配,语法规则类似C if (条件){...} ( 可用于: server,location )  ## 检查一个条件是否符合,如果条件符合,则执行大括号内的语句.不支持嵌套,不支持多条件 &&

Nginx 实现 Rewrite 跳转

文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 上一篇文章对Nginx的Location配置进行了讲解,本篇主要对于Nginx中的Rewrite跳转进行讲解.因为目前很多工作前端开发都会选择使用Nginx作为反向代理服务器,但是平时业务需要难免碰到重写URL,Nginx的Rewrite跳转有什么使用场景呢? 公司更换域名需要访问旧域名时跳转到新域名 请求静态文件跳转到CDN 根据用户设备不同跳转到不同站点(pc端,移动端) 不得不说的是Apache服务器

nginx之rewrite相关功能

Nginx Rewrite相关功能 Nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库,nginx的正则表达式底层依赖于PCRE库,PCRE是用perl语言写的:rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也

Nginx 笔记与总结(12)Nginx URL Rewrite 实例(ecshop)

访问项目地址:http://192.168.254.100/ecshop 某个商品的 URL:http://192.168.254.100/ecshop/goods.php?id=3 现在需要实现把以上 URL 改写成 http://192.168.254.100/ecshop/goods-3.html(ecshop 支持的简单重写模式) 此时访问 http://192.168.254.100/ecshop/goods-3.html 显示 404: 编辑 nginx 配置文件 nginx.con