在Nginx中使用rewrite配置


纸上得来终觉浅,绝知此事要躬行。

在Nginx中使用rewrite配置问号


  • 早上吃了早餐就到了公司,刚刚坐下并顺便泡了一杯枸杞水,还没喝就匆匆打开电脑,于是乎就收到微信群里的一个小需求,大致要求就是将 /api/v1/game/data?id=<game_id> 新网站路径地址映射到 http://gameid.escape.com/api/v1/new_game/<game_id> 老网站的 API 上面,给开发提供获取游戏用户信息的接口。因为我们使用的 nginx 进行路由配置的,所以最先想到的就是使用 proxy_pass 直接代理到对应的路径位置上。
server {
    listen       80;
    server_name  gameid.escape.com;

    access_log /var/log/nginx/gameid.nginx.access.log  main;
    error_log  /var/log/nginx/gameid.nginx.error.log   error;

    location / {
        return 404;
    }

    location ~ /api/v1/game/data\?id=(.*) {
        proxy_pass http://gameid.escape.com/api/v1/new_game/$1;
    }
}
  • 本以为就这么简单就完事儿了,但是通过 nginx -t 监测了下配置文件,发现居然报错了。查了下,发现通过 proxy_pass 配置的路径不能包含 URI 部分。分别是:location 字段中使用正则表达式内部命名的 location 字段包含 if 声明包含 limit_except 块,我们这里就是使用了正则表达式。
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, \
or inside named location, or inside “if” statement, or inside “limit_except” block ...
  • 经过不断的尝试也分析了一下原因,发现是因为路径中的 ? 导致的 rewrite 的匹配规则并没有生效。后来,在谷歌帮助下才发现原来问号在 nginx 中是有特殊逻辑处理的。

    • [1] Nginx 在进行 rewrite 正则匹配的时候,只会将 url? 前面的部分拿出来匹配
    • [2] 匹配完成后,将 ? 后面的内容将自动追加到 url 中(包含 ? 字符在内)
    • [3] 如果需要匹配 ? 后面的内容,则请使用 $query_string 字段变量来进行正则匹配
  • 这样就好办了,换个方式匹配一下就好了,仅为此做个笔记。

server {
    listen       80;
    server_name  gameid.escape.com;

    access_log /var/log/nginx/gameid.nginx.access.log  main;
    error_log  /var/log/nginx/gameid.nginx.error.log   error;

    location / {
        return 404;
    }

    location /api/v1/ {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_http_version 1.1;
        if ($request_uri ~* "/api/v1/game/data\?id=(.*)") {
            set $id $1;
            rewrite     .*  /api/v1/new_game/$id  break;
            proxy_pass  http://gameid.escape.com;
        }
    }
}

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !