[spring cloud] [error] java.lang.IllegalStateException: Only one connection receive subscriber allowed.
前言
最近在开发api-gateway的时候遇到了一个问题,网上能够找到的解决方案也很少,之后由公司的大佬解决了这个问题。写下这篇文章记录一下解决方案。希望可以帮助到更多的人。
环境
- java版本:8
- 框架:spring-cloud 2.0.0.RC1
介绍
api-gateway主要接收前端请求,然后对请求的数据进行验证,验证之后请求反向代理到服务器。当请求 method 为 GET 时,可以顺利通过api-gateway。当请求 method 为 POST 时,api-gateway则会报如下错误:
2018-07-18 11:49:04.073 ERROR 3025 --- [ctor-http-nio-4] .a.w.r.e.DefaultErrorWebExceptionHandler : Failed to handle request [POST http://localhost:9000/api/hello] java.lang.IllegalStateException: Only one connection receive subscriber allowed.
at reactor.ipc.netty.channel.FluxReceive.startReceiver(FluxReceive.java:276) ~[reactor-netty-0.7.5.RELEASE.jar:0.7.5.RELEASE]
at reactor.ipc.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:127) ~[reactor-netty-0.7.5.RELEASE.jar:0.7.5.RELEASE]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) ~[netty-common-4.1.22.Final.jar:4.1.22.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) ~[netty-common-4.1.22.Final.jar:4.1.22.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463) ~[netty-transport-4.1.22.Final.jar:4.1.22.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) ~[netty-common-4.1.22.Final.jar:4.1.22.Final]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_171]
错误分析
实际上spring-cloud-gateway反向代理的原理是,首先读取原请求的数据,然后构造一个新的请求,将原请求的数据封装到新的请求中,然后再转发出去。然而我们在他封装之前读取了一次request body,而request body只能读取一次。因此就出现了上面的错误。
解决方案
对于上面的错误我们给出的解决方案是:
读取request body的时候,我们再封装一次request,转发出去
下面是我们的代码:
@Component
public class PostFilter extends AbstractNameValueGatewayFilterFactory { private static final String X_APP_ID_HEADER = "X-app-id";
public static final String X_FORWARDED_FOR = "X-Forwarded-For"; @Override
public GatewayFilter apply(NameValueConfig nameValueConfig) {
return (exchange, chain) -> {
URI uri = exchange.getRequest().getURI();
URI ex = UriComponentsBuilder.fromUri(uri).build(true).toUri();
ServerHttpRequest request = exchange.getRequest().mutate().uri(ex).build();
if("POST".equalsIgnoreCase(request.getMethodValue())){//判断是否为POST请求
Flux<DataBuffer> body = request.getBody();
AtomicReference<String> bodyRef = new AtomicReference<>();//缓存读取的request body信息
body.subscribe(dataBuffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer());
DataBufferUtils.release(dataBuffer);
bodyRef.set(charBuffer.toString());
});//读取request body到缓存
String bodyStr = bodyRef.get();//获取request body
System.out.println(bodyStr);//这里是我们需要做的操作
DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer); request = new ServerHttpRequestDecorator(request){
@Override
public Flux<DataBuffer> getBody() {
return bodyFlux;
}
};//封装我们的request
}
return chain.filter(exchange.mutate().request(request).build());
};
} protected DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8); NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
}
至此,该问题得到解决。
[spring cloud] [error] java.lang.IllegalStateException: Only one connection receive subscriber allowed.的更多相关文章
- Spring Cloud Hystrix java.lang.NoClassDefFoundError: org/aspectj/lang/JoinPoint 问题
环境:spring boot: 1.3.7 spring cloud : Brixton.SR5 <parent> <groupId>org.springframewo ...
- java.lang.IllegalStateException: Failed to load ApplicationContext selenium 异常 解决
WARN <init>, HHH000409: Using org.hibernate.id.UUIDHexGenerator which does not generate IETF R ...
- maven打包错误:java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.118 sec <<< FAILURE! - in ...
- java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
java.lang.IllegalStateException: Not allowed to create transaction on sharedEntityManager - use Spri ...
- Spring Scheduled定时任务报错 java.lang.IllegalStateException: Encountered invalid @Scheduled method 'xxx': For input string: "2S"
报错信息如下: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ding ...
- 【spring boot】【elasticsearch】spring boot整合elasticsearch,启动报错Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8
spring boot整合elasticsearch, 启动报错: Caused by: java.lang.IllegalStateException: availableProcessors ], ...
- spring低版本报错:java.lang.IllegalStateException: Context namespace element ‘annotation-config’ and its parser class [*] are only available on
参考来源:http://blog.csdn.net/sunxiaoyu94/article/details/50492083 使用spring低版本(2.5.6),使用jre 8发现错误: Unexp ...
- spring mvc处理http请求报错:java.lang.IllegalStateException: getInputStream() has already been called for this request
发送post请求到controller处理失败,报错日志如下: java.lang.IllegalStateException: getInputStream() has already been c ...
- java.lang.IllegalStateException: Active Spring transaction synchronization or active JTA transaction with specified [javax.transaction.TransactionManager] required
错误信息: java.lang.IllegalStateException: Active Spring transaction synchronization or active JTA trans ...
随机推荐
- java——包装类数据缓存 ==号详解
Java对部分经常使用的数据采用缓存技术,即第一次使用该数据则创建该数据对象并对其进行缓存, 当再次使用等值对象时直接从缓存中获取,从而提高了程序执行性能.(只对常用数据进行缓存) Java中只是对部 ...
- 【原创】大叔经验分享(68)maven工程查看jar包依赖
1 idea 结果 2 maven命令 $ mvn dependency:tree 结果 [INFO] +- org.springframework.boot:spring-boot-starter- ...
- luogu题解 P3811 【【模板】乘法逆元】
upd--7.6 原线性求逆元代码有另一种更优写法 题目链接: https://www.luogu.org/problemnew/show/P3811 概念: 一想到JXOI 2018考场上忘记逆元怎 ...
- SpringBoot整合Mybatis关于分页查询的方法
最近公司在用到SpringBoot整合Mybatis时当web端页面数据增多时需要使用分页查询以方便来展示数据.本人对分页查询进行了一些步骤的总结,希望能够帮助到有需要的博友.如有更好的方式,也希望评 ...
- O046、掌握Cinder 的设计思想
参考https://www.cnblogs.com/CloudMan6/p/5578673.html 从 volume 创建流程看 cinder-* 子服务如何协同工作 对于 Cinder ...
- Typora入门:全网最全教程
目录 简介 Markdown介绍 常用快捷键 块元素 换行符 标题级别 引用文字 无序列表 有序列表 任务列表 代码块 数学表达式 插入表格 脚注 分割线 目录(TOC) 跨度元素 链接 网址 图片 ...
- Centos7:ActiveMQ安装,配置及使用
解压缩ActiveMQ 的压缩包 使用 命令在bin目录下 ./activemq stat//开启 ./activemq stop//关闭 ./activemq status//状态 进入管理后台 U ...
- python之jupyter notebook
jupyter是一种交互式计算和开发环境的笔记,ipython命令行比原生的python命令行更加友好和高效,还可以运行web版的界面,支持多语言,输出图形.音频.视频等功能. 安装 pip inst ...
- 二、Nginx多站点配置(参考宝塔的)分析
一.基于宝塔配置文件分析(站的配置文件) 新增的站点配置即添加server并包含在nginx内 查找文件: 文件内容: 二.伪静态 伪静态是一种可以把文件后缀改成任何可能的一种方法,如果我想把php文 ...
- fragment初步认识