记一次请求头header丢失问题排查实录
前言
前端小王需要调用兄弟部门老张的后端接口,老张提供的接口,需要token鉴权才能调用成功。当小王按约定携带token调用老张的接口时,起先因为跨域问题,导致前端小王没法成功请求老张的接口。于是小王就跟老张说,能不能他那边配置下允许跨域。但小王是一个很有原则的人,他说这个接口是要给N个部门调用的,不可能给这些调用部门都配置允许跨域,不然口子一旦开了,后面就没完没了,他让小王自己想办法解决跨域。后面小王就把事情向上反馈,小王的领导就跟小王说,我们自己搭个反向代理,通过反向代理解决跨域问题。本文的素材就是来源于此次搭建反向代理后,发生的故事
故事延续
因为前端本来就是基于nginx进行代理,因此小王就直接把老张的接口地址,配置在nginx上。配好后小王就找老张再一次联调,这次跨域的问题是解决了,但是接口返回”系统出现异常,请联系管理员”,小王就问让老张排查一下是啥情况,老张看了日志说,是token空了,就问小王是不是token没传,小王信誓旦旦说传了,并把传token的截图丢给老张。
到这事情就很诡异了,小王明明按老张的接口要求,传了token,但为啥老张没接收到token,后边小王就说老张的接口有bug,老张的第一反应是,不可能,这个接口已经提供给好几个系统使用了,他们都没问题。小王就说他们使用没问题,不能代表你接口就是没bug,我这边都按你要求的格式传了,你却没收到,那肯定是你那边问题了。
因为小王和老张都觉得自己请求或者调用没问题,就找了在公司很有威望的程序员老黄来评判,老黄毕竟没参与过小王或者老张的业务项目,他就没从业务入口,而是从端到端的请求入手,他先分析一下请求链路,其次看了一下请求参数,其中token的header参数的key,引起了他注意。这个token的header参数key,为auth_token,于是他就让小王在nginx 的http或者server块配置如下参数
underscores_in_headers on
然后再试下。这次接口很丝滑的通了,小王和老子对老黄的敬仰之情又多了一分
复盘
1、为什么加了underscores_in_headers on,接口就好使了?
我们直接贴官网的说明
他的中文大意是当客户端请求头的字段中带有下划线,nginx默认会将该字段标识为无效字段
既然是无效了,当然token就空了。详细可以看官方链接
http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
其实还有另外一种解法就是大家约定好,不要用下划线,比如将auth_token,改为auth-token.。不过如果涉及到多方系统已经使用了下划线的情况,此时要推进改动,可能就要涉及很多沟通成本了
总结
本文虽然说是讲请求头header丢失的问题,但更多是复现一个开发联调时候的场景,很多时候我们都会觉得我们开发出来的东西没问题,会带有一种迷之自信,其次我文章故意将”系统出现异常,请联系管理员”这个返回值抛出来,这个返回值如果面向对象是业务方,大体是问题不大,但如果是面向群体是开发,无形中就增加沟通成本。很多时候我们大部分的联调时间,其实是耗费在沟通上。
最后补充一下附录跨域和允许下划线访问的内容就当做一个彩蛋,本文的真实场景,其实是通过nginx-ingress来做7层转发
附录
kubectl.kubernetes.io/last-applied-configuration: |-
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728008;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,PATCH,OPTIONS';
return 200;
}
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/cors-allow-credentials: 'true'
nginx.ingress.kubernetes.io/cors-allow-headers: >-
DNT,x-app-id,x-tenant-id,x-user-id,Authorization,Accept,Origin,Keep-Alive,User-Agent,access-control-allow-origin,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,systemId,Cookie,x-agent-type,x-noauth,isrefreshtoken,auth_token
nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS
nginx.ingress.kubernetes.io/cors-allow-origin: '*'
nginx.ingress.kubernetes.io/enable-cors: 'true'
nginx.ingress.kubernetes.io/proxy-body-size: 300m
nginx.ingress.kubernetes.io/server-snippet: |
underscores_in_headers on;
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
其中
kubectl.kubernetes.io/last-applied-configuration: |-
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728008;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,PATCH,OPTIONS';
return 200;
}
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/cors-allow-credentials: 'true'
nginx.ingress.kubernetes.io/cors-allow-headers: >-
DNT,x-app-id,x-tenant-id,x-user-id,Authorization,Accept,Origin,Keep-Alive,User-Agent,access-control-allow-origin,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,systemId,Cookie,x-agent-type,x-noauth,isrefreshtoken,auth_token
nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST, OPTIONS
nginx.ingress.kubernetes.io/cors-allow-origin: '*'
nginx.ingress.kubernetes.io/enable-cors: 'true'
是允许跨域请求的部分
其中
nginx.ingress.kubernetes.io/server-snippet: |
underscores_in_headers on;
是允许请求头包含下划线的部分
当然还可以通过在ingress-nginx-controller的configmap里添加
enable-underscores-in-headers: "true"
开启全局配置允许请求头包含下划线
示例配置
apiVersion: v1
data:
allow-snippet-annotations: "true"
enable-underscores-in-headers: "true"
use-forwarded-headers: "true"
kind: ConfigMap
....省略其他