spring Cloud gateway rest调用报错

问题描述

有时候我们需要在spring cloud gateway中进行一些远程接口的调用,比如网关的鉴权,需要调用rpc接口查询用户信息,如果直接调用feign接口,会出现如下报错:

1
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:83)	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 

问题原因

这是因为新版的 gateway 采用的是非阻塞式编程,但是在获取注册中心实例时,调用了block()方法阻塞式获取实例,只要你敢 block,就会

1
throw new IllegalStateException("block()/blockFirst()/blockLast() are blocking, which is not supported in thread " + Thread.currentThread().getName());
1
public <T> ServiceInstance choose(String serviceId, Request<T> request) {        ReactiveLoadBalancer<ServiceInstance> loadBalancer = this.loadBalancerClientFactory.getInstance(serviceId);        if (loadBalancer == null) {            return null;        } else {            Response<ServiceInstance> loadBalancerResponse = (Response)Mono.from(loadBalancer.choose(request)).block();            return loadBalancerResponse == null ? null : (ServiceInstance)loadBalancerResponse.getServer();        }    } 	final T blockingGet() {		if (Schedulers.isInNonBlockingThread()) {			throw new IllegalStateException("block()/blockFirst()/blockLast() are blocking, which is not supported in thread " + Thread.currentThread().getName());		}		if (getCount() != 0) {			try {				await();			}			catch (InterruptedException ex) {				dispose();				throw Exceptions.propagate(ex);			}		} 		Throwable e = error;		if (e != null) {			RuntimeException re = Exceptions.propagate(e);			//this is ok, as re is always a new non-singleton instance			re.addSuppressed(new Exception("#block terminated with an error"));			throw re;		}		return value;	}

解决方式

问题找到了,解决起来就简单了,我们只需要重写获取实例的方法就好了,上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    @<!-- toc -->
<meta name="referrer" content="no-referrer" />
Bean public BlockingLoadBalancerClient blockingLoadBalancerClient(ReactiveLoadBalancer.Factory < ServiceInstance > loadBalancerClientFactory, DiscoveryClient discoveryClient) {
return new BlockingLoadBalancerClient(loadBalancerClientFactory) {@
Override public < T > ServiceInstance choose(String serviceId, Request < T > request) {
List < ServiceInstance > instanceList = discoveryClient.getInstances(serviceId);
return loadBalancerInstance(instanceList);
}
};
}
private static ServiceInstance loadBalancerInstance(List < ServiceInstance > instanceList) {
if (CollUtil.isEmpty(instanceList)) {
return null;
}
if (instanceList.size() == 1) {
return instanceList.get(0);
} // 随机负载 int index = RandomUtil.randomInt(0, instanceList.size()); return instanceList.get(index); }

这里的负载均衡是随机负载的,各位可以根据自己的机器数量,设置不同的负载均衡策略(我这生产其实只有一个节点,负载不负载无所谓)