[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 ...
随机推荐
- 怎样安装 cnpm 并切换到淘宝镜像?
如果不使用 vpn , 在国内直接使用 npm 的官方镜像会很慢,这里推荐使用淘宝 NPM 镜像.淘宝 NPM 镜像是一个完整的 npmjs.org 镜像,可以用此代替官方版本(只读). 操作方法如下 ...
- Scala学习三——数组相关操作
一.若长度固定则使用Array,若长度可能有变化则使用ArrayBuffer 固定长度数组: 如val nums=new Array[Int](10) //10个整型数组,所有元素初始化为0; val ...
- springMVC 接受map参数的写法
<form > <input type="hidden" name="map['userKey']" value="11111&qu ...
- 【原创】大叔案例分享(5)id打通
经常有一些需要做id打通的场景,比如用户id打通等, 问题抽象是每条数据都可以解析出一个或多个kv pair:(id_type,id),然后需要将某一个kv pair匹配的多条数据进行merge: 比 ...
- python之uWSGI和WSGI
WSGI协议 首先弄清下面几个概念:WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web ...
- java反射浅谈 part1--反射机制的定义,作用,原理
一.定义 在运行过程中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:还可以通过反射创建对象,这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- windows环境下,kafka常用命令
创建topics kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partition 3 - ...
- 读书笔记《Oracle从入门到精通》
目录 一.SQL基础 1.SQL种类 2.常用数据类型 3.DDL 4.约束 5.DML语句 二.SELECT语句 1.结果集'*'与指定列 2.拼接符 || 3.substr函数 4.instr函数 ...
- DNS缓存失败怎么解决?
DNS的中文名是域名系统,是域名和IP地址相互映射的一个分布式数据库.有了DNS,我们上网时直接输入网站域名(即网址)即可,而不用输入网站的IP地址访问网站,对于用户来说比较方便记忆和访问. 每次当我 ...
- ubuntu系统搭建samba服务
安装samba服务 # apt-get install samba 创建一个samba服务的分享目录 # mkdir /share 创建一个samba服务限制的用户及组 #useradd public ...