0%

spring cloud gateway部署到k8s上UrlEncode问题

问题

k8singress使用的是ingress-nginx.

项目中用到了spring cloud gatewayAPI网关,部署环境有dockerk8s等. 测试出现一个问题:
请求的URL路径中如果出现了中文参数,如http://localhost:8080/test?param=你好,如果部署在docker或者裸机上,后台服务接收到的参数param你好,但是如果部署在k8s上,后台接收到的参数可能是UrlEncode之后的%E4%BD%A0%E5%A5%BD,这不是后台需要的. 虽然可以在后台通过URLDecoder.decode(name, "UTF-8")强制解码,不过比较麻烦.

分析

测试中发现,

  • 如果直接将后台服务部署到k8s上,通过service -> ingress暴露出来,不管是通过k8sClusterIP,如http://10.96.240.18:8080/test?param=你好, 还是通过ingress域名http://local.com/test?param=你好请求后台服务,后台能够正确接收到参数为你好,证明问题可能不是因为部署在k8s上造成的,只可能是spring cloud gatewayAPI网关原因;
  • 但是部署在docker或者裸机上,通过spring cloud gateway网关请求后台服务,后台能够正确接收到参数为你好,证明网关也是没有问题的,问题只可能是部署环境k8s的原因;
  • 如果将网关服务部署到k8s上,又有两种情况:
    • 通过ingress域名请求网关 -> 后台,后台接收到的参数是%E4%BD%A0%E5%A5%BD,看似是网关的问题;
    • 通过ClusterIP请求网关 -> 后台,后台接收到的参数是你好,这又证明网关没问题,看似是ingress的问题,但前面也证明了ingress可以正确传递中文字符,非常的奇怪!
  • spring cloud gateway中所有的Filter全部注释掉,发现通过ingress域名请求网关 -> 后台,后台也能正确的接收到中文参数,证明还是网关的问题,而且这个问题只有部署在k8s中搭配ingress-nginx使用时才会暴露.

解决

依次将注释掉的Filter加回去,证明问题出现在class XXXX extends ForwardedHeaderFilter这个类上.这个类用于设置网关跨域访问和网关本身接口权限验证.

测试发现,即使只注释成下面这样,还是会有问题,但是注释掉@Component,就没有问题.应该是super.filter(exchange, chain)父类这个方法有问题.

@Component
@Slf4j
public class AuthTokenFilter extends ForwardedHeaderFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //跨域问题 接口权限验证 TODO
        return super.filter(exchange, chain);
    }
}

改成下面这样测试可以解决问题.

@Component
@Slf4j
public class AuthTokenFilter extends ForwardedHeaderFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        //跨域问题 接口权限验证 TODO
        return chain.filter(exchange);
    }
}