【已解决/已分析】spring cloud gateway的POST请求问题解决:Only one connection receive subscriber allowed

环境

JDK1.8
spring boot 2.0.6.RELEASE

问题表现

使用POST请求gateway时,后端微服务拿不到body信息,仿佛就是gateway吞掉了body(其实就是);
gateway开DEBUG模式,查看报如下错误:

java.lang.IllegalStateException: Only one connection receive subscriber allowed. 	at 
reactor.ipc.netty.channel.FluxReceive.startReceiver(FluxReceive.java:279) 	at 
reactor.ipc.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:129) 	at 
io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:163) 	at 
io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java) 	at 
io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) 	at 
io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:446) 	at 
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) 	at 
java.lang.Thread.run(Thread.java:745) 大意就是netty的request body

只能读取一次,第二次读取就报这个错误了。

问题原因

翻查GitHub终于找到,spring boot在2.0.5版本如果使用了WebFlux就自动配置HiddenHttpMethodFilter过滤器。
查看源码发现,这个过滤器的作用是,针对当前的浏览器一般只支持GET和POST表单提交方法,如果想使用其他HTTP方法(如:PUT、DELETE、PATCH),就只能通过一个隐藏的属性如(_method=PUT)来表示,那么HiddenHttpMethodFilter的作用是将POST请求的_method参数里面的value替换掉http请求的方法。
想法是很好的,用一种折中的方法来支持使浏览器支持restful方法。

如果只是使用spring boot,一切都是没有问题的,因为使用的过程中,不需要我们自己解析request body,到controller这一层,这一切就已经完成的了。

但是spring cloud gateway需要,因为它的做法就是拿到原始请求信息(包括request body),再重新封装一个request路由到下游微服务,所以上面的问题就在于:

  1. HiddenHttpMethodFilter读取了一次request body
  2. gateway的封装自己的request时,去读取request body,就报错了

所以这个是spring cloud gateway和spring boot开发者没协商好,都去读取request body的问题。

问题解决方案

HiddenHttpMethodFilter是spring boot在2.0.5版本自动引入的,将版本降到2.0.4即可。
如果不降版本,也可以自己重写HiddenHttpMethodFilter来覆盖原来的实现,如下:

@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
    return new HiddenHttpMethodFilter() {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
            return chain.filter(exchange);
        }
    };
}

filter方法什么都不做,自然就不会读取request body了,你可能会想,那不就不支持HiddenHttpMethodFilter的功能了吗,其实gateway本身就不应该做这种事情,原始请求是怎样的,转发给下游的请求就应该是怎样的。下游服务如果使用的是也是spring boot的服务,那么下游服务自己会做HiddenHttpMethodFilter的功能。

这也是gateway官方开发者目前所提出的解决方案。

更多信息可以查看这个issues
spring boot的2.0.5版本添加了HiddenHttpMethodFilter内容,入口

如果想查看其他spring cloud gateway的案例和使用,可以点击查看

转自:spring cloud gateway的POST请求问题解决:Only one connection receive subscriber allowed

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值