问题
k8s中ingress使用的是ingress-nginx.
项目中用到了spring cloud gateway做API网关,部署环境有docker、k8s等. 测试出现一个问题:
请求的URL路径中如果出现了中文参数,如http://localhost:8080/test?param=你好,如果部署在docker或者裸机上,后台服务接收到的参数param是你好,但是如果部署在k8s上,后台接收到的参数可能是UrlEncode之后的%E4%BD%A0%E5%A5%BD,这不是后台需要的. 虽然可以在后台通过URLDecoder.decode(name, "UTF-8")强制解码,不过比较麻烦.
分析
测试中发现,
- 如果直接将
后台服务部署到k8s上,通过service -> ingress暴露出来,不管是通过k8s中ClusterIP,如http://10.96.240.18:8080/test?param=你好, 还是通过ingress域名http://local.com/test?param=你好请求后台服务,后台能够正确接收到参数为你好,证明问题可能不是因为部署在k8s上造成的,只可能是spring cloud gateway做API网关原因; - 但是部署在
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);
}
}