毋庸多言,Nginx作为一款高性能的HTTP和反向代理服务器,现在几乎成了软件开发中的必备技能,特别是在java web应用程序中,基本上变成了标准配置,它经常用来作为反向代理,以提升系统的吞吐量和可用性。
 

然而,Nginx中的一项默认配置却让我掉到了一个大坑里,差点让我的职场生涯折戟沉沙。

事情是这样的,我们的系统调用另外一个系统的接口,服务方的接口再返回对应的结果,总体来讲就是这么一个非常常见、简单的应用场景,比如我们的系统A,组织好对应的参数,调用系统B,B再根据传入的参数,返回满足条件的结果,如下图所示:

nginx首页在哪个路径下_nginx首页在哪个路径下

这样的场景简直太常见了,几乎不值一提,只要你的系统跟微服务沾点边,这样的接口调用是非常自然的,甚至显得有些平庸。当然,我也是这么认为的。

后来B系统进行迁移,需要重新部署,我们的系统当然也需要对接,领导问我大概要多久可以对接完成,我当时想,就是改一下调用地址而已,根本不需要费什么功夫,不过多年的踩坑经验告诉我,开发计划需要留出一些buffer,对自己是有好处的,不过再怎么留buffer,一天的时间再怎么样也是够的了,不就是改一下调用地址吗?

但是,B系统迁移完成后,我们把接口的地址也进行了相应的修改,然而,我们传递过去的参数中,有一个参数B系统就是收不到,ip是可以ping通,也没有防火墙拦截,就是收不到参数,我们的日志里有这个参数的信息,然而B系统的程序日志里就是没有。真是太奇怪了,问题到底出在哪里,之前明明是好的,现在系统只是做了一下迁移,只是把ip换成新的而已,为什么参数就传递不过去了呢?

为了更清晰的说明这个问题,我在本地搭了一个很简单的“世界你好”的程序来模拟演示当时的情况。用Spring boot写个Hello World:

@RestController
@RequestMapping("/para")
public class ParameterController {


@GetMapping("hello")
public String helloworld(HttpServletRequest request){


return "Hello World!";
    }
}

端口设置为8081,我们用Postman来测试,结果完全符合我们的预想,当然,稍微有点特别的是,我们在header里面也有参数:

nginx首页在哪个路径下_接口_02

我们debug一下看看程序里收到的参数是什么样的。在这里,我们可以把Postman理解为系统A,因为它是服务的请求方嘛,而刚才的Hello World程序就是系统B,它接收参数并且返回结果。

nginx首页在哪个路径下_java_03

没问题,程序收到了传递过来的参数,一切正常。

然而,当我们配置了nginx,请求先到nginx再转发到tomcat,上面有个参数竟然莫名其妙的消失了。

在nginx里配置如下,其他配置项未做改变:

location / {
proxy_pass http://localhost:8081/para/;
}

继续用Postman来测试,参数保持不变,当然,这个时候请求的地址需要修改为:http://localhost/hello,让请求先打到nginx上。

然而,让人费解的是,Hello World程序竟然收不到my_token的参数值了:

nginx首页在哪个路径下_接口_04

明明这个参数有值,为什么就为null值了呢?另外一个参数info,却完全没有问题,真是奇怪。

最后,经过各种探索(其实就是搜索引擎了,面向搜索引擎编程。。。???),终于知道,对于带下划线的请求头参数,nginx默认是会忽略的,我们在nginx里修改一下参数的配置,把underscores_in_headers修改为on(默认为off),同时reload一下:

underscores_in_headers on;

再次用Postman发送请求:

nginx首页在哪个路径下_nginx首页在哪个路径下_05

继续断点debug看看,这时候,my_token就可以正常收到参数值了:
 

nginx首页在哪个路径下_接口_06

 nginx的官网对此也有说明  

nginx首页在哪个路径下_nginx首页在哪个路径下_07

问题终于水落石出,谜底也终于解开了:系统B进行系统迁移后,nginx的配置没有进行相应的修改,由于有专门的运维人员在进行这样的配置,所以这一块也超出了我们的职责范围,导致了长时间没有定位到问题原因,总是从程序本身去找错误,方向一旦错了,解决起来就比较耗时间了。