全站https发现的spring gateway header覆盖 (bug?)问题

全站https发现的spring gateway header覆盖(bug?)问题


1. 需求


项目环境准备换成https环境,http也需要保留,两种方式都可以访问
某些地址需要进行双向认证

当前环境结构大概如下:

nginx(http) -> nginx(http) -> gateway(http) -> tomcat(http);

改变后的结构:

nginx(https,http) -> nginx(http) -> gateway(http) -> tomcat(http);


2.配置 https


这种配置网上有很多,这里不详细说明,配置大概如下:

    listen 80 default;
    listen 443 ssl;
    ssl_certificate ssl.crt;
    ssl_certificate_key ssl.key;


location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host:$server_port;
    proxy_pass   http://endpoint:8084;
    index  index.html;
}

---
配置完成,访问系统也没问题

3.问题

当后端出现进行Redirect 重定向跳转 301,302 时,地址就会变得不对,比如本来是访问的https,结果跳转到http页面

启动项目(tomcat)进行调试,发现request.getScheme() 拿到的竟然是 http,这不正常啊,明明已经设置了 X-Forwarded-Proto

再进行调试,发现 header 中竟然没有 X-Forwarded-Proto ,想到是不是上层(gateway)是不是拦截,没有传递

随即调试 gateway, 发现在 NettyRoutingFilter 中,被覆盖了!!!

目前使用的gateway版本(spring-cloud-gateway-core.2.1.2),与最新的代码进行了对比,该代码也有太大变化
随即反复读了源码,还是找不到能友好的重写与修复的方法
github 也提交了问题,但过去几天也没人理,而且还发现有其它人出现跟我一样的问题;
https://github.com/spring-cloud/spring-cloud-gateway/issues/1786

4.奇怪现象

gateway 不是不传递 X-Forwarded-Proto,而是因为 X-Forwarded-Proto 与 X-Forwarded-For 计算出的 hashCode(?) 一致,导致相互被覆盖
这真的是一个有趣的问题(BUG),规则大概如下:
    X-Forwarded-For, X-Forwarded-Proto :  前者覆盖后者
    X-Forwarded-For, x-forwarded-proto :  后者覆盖前者

大概好像是因为(猜测),小写的header在map中比大写的排在后面,然后在遍历的时候后面的覆盖了前面的
NettyRoutingFilter 中创建转换 DefaultHttpHeaders (netty) 时,因为两个header计算出来的hashCode一致,就被覆盖了
---
通过查看源码,发现好像DefaultHttpHeaders控制了header个数,最多只传递16个
而且这个数量在代码中是写死的,无法通过参数等形式传入

---
不理解一个这么简单的逻辑会有这种实现方式(摊手),如果有人知道的话也烦请告诉一声


5.过程

经过各种测试,比如 
自定义header,声明一个 my-forwarded-proto,发现这个被丢弃,无法传递到业务(tomcat);

只传 x-forwarded-proto, 业务获取的scheme还是 http。 查看header,x-forwarded-proto有被正确传递(value: https,http)。
再进一步查看,发现tomcat获得scheme的逻辑是: 只要其中有一个不是https,scheme就不是https;

想将gateway切换到tomcat容器,也因为各种配置问题无法进行

6.解决

也不是解决,对于上面的问题(gateway bug?)找不到解决方案,死磕问题几天,又没有进展

最终通过 nginx 的 proxy_redirect 重新对路径进行了跳转:
如果后端返回了当前系统的路径,然后重写路径,将scheme进行替换,达到各环境(http,https)的统一


proxy_redirect ~^http://ip/(.*) $scheme://ip/$1;


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值