纸上得来终觉浅,绝知此事要躬行。
- 早上吃了早餐就到了公司,刚刚坐下并顺便泡了一杯枸杞水,还没喝就匆匆打开电脑,于是乎就收到微信群里的一个小需求,大致要求就是将
/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
字段变量来进行正则匹配
- [1]
这样就好办了,换个方式匹配一下就好了,仅为此做个笔记。
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;
}
}
}