[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 ...
随机推荐
- linq多个条件
public static class PredicateBuilder { /// <summary> /// 机关函数应用True时:单个AND有效,多个AND有效:单个OR无效,多个 ...
- cookie转换成字典类型方便scraoy 使用
#bakooie装换成紫电模式方便scrapy使用 cookid = "_ga=GA1.2.1937936278.1538889470; __gads=ID=1ba11c2610acf504 ...
- 【Git的基本操作二】添加、提交、查看状态
添加.提交.查看状态操作 查看状态: git status
- 林大妈的CSS知识清单(二)可见格式化模型(内含margin塌陷与浮动闭合的解决方案)
盒模型.浮动和定位是CSS中最重要的三个概念.它们共同决定了一个元素在页面中以怎样的形式进行排布与显示. 一.盒模型 1. 定义 盒模型是CSS的核心概念.一个页面中,所有的元素(不管他最终显示是圆形 ...
- Java高并发程序设计学习笔记(六):JDK并发包(线程池的基本使用、ForkJoin)
转自:https://blog.csdn.net/dataiyangu/article/details/86573222 1. 线程池的基本使用1.1. 为什么需要线程池1.2. JDK为我们提供了哪 ...
- SQL优化策略
mysql添加索引 1.主键索引LATER TABLE 'table_neme' ADD PRIMARY KEY('column');2.唯一索引unique空串(null)可以放多个 如果是具体的内 ...
- JavaScript【对象的学习】
JavaScript对象的了解 1.js的String对象创建String对象:var str = "abc";方法和属性(参照W3C文档详细学习)属性 length:字符串的长度 ...
- CTAP: Complementary Temporal Action Proposal Generation论文笔记
主要观点:基于sliding window(SW)类的方法,如TURN,可以达到很高的AR,但定位不准:基于Group的方法,如TAG,AR有明显的上界,但定位准.所以结合两者的特长,加入Comple ...
- MySQL查询数据库中所有数据表的数据条数
select table_name,table_rows from information_schema.tables where TABLE_SCHEMA = '数据库名称' order by ta ...
- Linux用户组管理及用户权限2
用户.组和权限管理 Multi-tasks,Multi-Users,多任务,多用户的计算机 每个使用者: 用户标识.密码: Authentication ...