需求
不修改代码的情况下,在nginx转发请求时修改response body获取期望值。
请求有2个特征唯一定位:
- url:/aaa/bbb/ccc/ddd
- 自定义header(区分版本):
System-Version: pro
不同版本会请求相同服务器下相同url
Tip:这么干的原因主要是由于上线管控,问题修复后不能随时上线。但是线上部分用户已经不能正常使用功能了,所以算是一个暂时解决方案,不提倡不鼓励这么干哇~
原返回值:
{
"code": 200,
"data": {
"deployAdmin": false,
"systemId": "aaa"
}
}
期望返回值:
// deployAdmin控制页面显示,这里期望为true
{
"code": 200,
"data": {
"deployAdmin": true,
"systemId": "aaa"
}
}
实现
基于基本nginx配置,不需安装额外模块(安装额外模块得找运维,也赶不及-_-)。
读取自定义header
首先,开启underscores_in_headers
解释:HTTP头部是否允许下划线。默认为off,表示HTTP头部的名称中不允许带“_”
语法:underscores_in_headers on | off;
默认:underscores_in_headers off;
配置块:http、server
然后,通过$http_
加自定义header读取目标请求头(纯小写,中划线替换为下划线)
比如:获取 System-Version
应写为 $http_system_version
# nginx.conf
server {
listen 80;
...
underscores_in_headers on;
...
location ~ ^/aaa/ {
...
if ($http_system_version = "pro") {
...
}
}
}
撰写AND条件
nginx配置中使用 if(a && b)
的条件判断是无效的。但需求中要求的条件是 url = '/aaa/bbb/ccc/ddd'
并且 $http_system_version = 'pro'
。解决思路是声明一个变量,每判断一个条件为true,就将变量修改一下,最后直接判断该变量是否达到了所有条件为true的修改状态即可。
# nginx.conf
location ~ ^/aaa/ {
...
set $a 0;
if ($http_system_version = "pro"){
set $a 1;
}
if ($request_uri ~ ^/aaa/bbb/ccc/ddd) {
set $a 1$a;
}
if ($a = '11') {
...
}
}
修改响应体
直接上这段逻辑完整配置
location ~ ^/aaa/ {
# 以/aaa开头的请求代理到 http://xxx.yyy.com
proxy_pass http://xxx.yyy.com;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# AND条件判断变量
set $a 0;
# 请求中自定义header头System-Version为"pro"
if ($http_system_version = "pro") {
set $a 1;
}
# 请求url为'/aaa/bbb/ccc/ddd'
if ($request_uri ~ ^/aaa/bbb/ccc/ddd) {
set $a 1$a;
}
# 两个条件都符合时return 期望返回值
if ($a = '11') {
return 200 '{"code":200,"data":{"deployAdmin":true,"systemId":"aaa"}}';
}
}
Tip: if后一定要跟空格,不然nginx会报错~
域名重定向
小记一下,跟本次需求无关联
服务器对应两个域名123.yy.com
与 456.yy.com
,用户访问123.yy.com
时,将请求重定向到456.yy.com
(此时浏览器地址栏url域名会被替换)。这种情况适用与新老域名过渡期~
if ($host = '123.yy.com') {
rewrite ^/(.*)$ http://456.yy.com/$1 permanent;
}
小记
有一个过滤器模块 ngx_http_sub_module
,它可以通过将一个指定的字符串替换为另一个字符串来响应,但需要安装,默认不带。
另:更灵活的配置可通过搭配lua
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。