Spring Cloud Gateway 使用 HystrixGatewayFilterFactory 熔断降级
Posted 抓手
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Gateway 使用 HystrixGatewayFilterFactory 熔断降级相关的知识,希望对你有一定的参考价值。
引入maven
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在配置文件,路由上添加HystrixGatewayFilterFactory过滤器,name为Hystrix。
spring:
cloud:
gateway:
routes:
- id: 用户服务
uri: lb://user-server
predicates:
- Path=/user-server/**
filters:
- name: Hystrix
args:
name: fallbackcmd
另外在配置文件上设置请求超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
# 请求超时时间5000毫秒
timeoutInMilliseconds: 5000
请求接口,并出发降级,返回如下:
"timestamp": "2022-08-16T01:23:11.939+0000",
"path": "/user-server/open/a",
"status": 504,
"error": "Gateway Timeout",
"message": "Response took longer than configured timeout"
使用自定义降级策略返回,配置文件修改,添加fallbackUri
spring:
cloud:
gateway:
routes:
- id: 用户服务
uri: lb://user-server
predicates:
- Path=/user-server/**
filters:
- name: Hystrix
args:
name: fallbackcmd
# 使用自定义fallback
fallbackUri: forward:/fallback
然后添加Fallback类
@RestController
public class FallbackController
@RequestMapping("/fallback")
public Object fallback()
// 这里可以自定义返回json内容
return "errorjson";
此时降级返回:
errorjson
org.springframework.cloud.gateway.filter.factory.HystrixGatewayFilterFactory 源码
public class HystrixGatewayFilterFactory extends AbstractGatewayFilterFactory<HystrixGatewayFilterFactory.Config>
public static final String FALLBACK_URI = "fallbackUri";
private final ObjectProvider<DispatcherHandler> dispatcherHandlerProvider;
// do not use this dispatcherHandler directly, use getDispatcherHandler() instead.
private volatile DispatcherHandler dispatcherHandler;
public HystrixGatewayFilterFactory(
ObjectProvider<DispatcherHandler> dispatcherHandlerProvider)
super(Config.class);
this.dispatcherHandlerProvider = dispatcherHandlerProvider;
private DispatcherHandler getDispatcherHandler()
if (dispatcherHandler == null)
dispatcherHandler = dispatcherHandlerProvider.getIfAvailable();
return dispatcherHandler;
@Override
public List<String> shortcutFieldOrder()
return Arrays.asList(NAME_KEY);
public GatewayFilter apply(String routeId, Consumer<Config> consumer)
Config config = newConfig();
consumer.accept(config);
if (StringUtils.isEmpty(config.getName()) && !StringUtils.isEmpty(routeId))
config.setName(routeId);
return apply(config);
@Override
public GatewayFilter apply(Config config)
//TODO: if no name is supplied, generate one from command id (useful for default filter)
if (config.setter == null)
Assert.notNull(config.name, "A name must be supplied for the Hystrix Command Key");
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName());
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(config.name);
config.setter = Setter.withGroupKey(groupKey)
.andCommandKey(commandKey);
return (exchange, chain) ->
RouteHystrixCommand command = new RouteHystrixCommand(config.setter, config.fallbackUri, exchange, chain);
return Mono.create(s ->
Subscription sub = command.toObservable().subscribe(s::success, s::error, s::success);
s.onCancel(sub::unsubscribe);
).onErrorResume((Function<Throwable, Mono<Void>>) throwable ->
if (throwable instanceof HystrixRuntimeException)
HystrixRuntimeException e = (HystrixRuntimeException) throwable;
HystrixRuntimeException.FailureType failureType = e.getFailureType();
switch (failureType)
case TIMEOUT:
return Mono.error(new TimeoutException());
case COMMAND_EXCEPTION:
Throwable cause = e.getCause();
/*
* We forsake here the null check for cause as HystrixRuntimeException will
* always have a cause if the failure type is COMMAND_EXCEPTION.
*/
if (cause instanceof ResponseStatusException || AnnotatedElementUtils
.findMergedAnnotation(cause.getClass(), ResponseStatus.class) != null)
return Mono.error(cause);
default: break;
return Mono.error(throwable);
).then();
;
//TODO: replace with HystrixMonoCommand that we write
private class RouteHystrixCommand extends HystrixObservableCommand<Void>
private final URI fallbackUri;
private final ServerWebExchange exchange;
private final GatewayFilterChain chain;
RouteHystrixCommand(Setter setter, URI fallbackUri, ServerWebExchange exchange, GatewayFilterChain chain)
super(setter);
this.fallbackUri = fallbackUri;
this.exchange = exchange;
this.chain = chain;
@Override
protected Observable<Void> construct()
return RxReactiveStreams.toObservable(this.chain.filter(exchange));
@Override
protected Observable<Void> resumeWithFallback()
if (this.fallbackUri == null)
return super.resumeWithFallback();
//TODO: copied from RouteToRequestUrlFilter
URI uri = exchange.getRequest().getURI();
//TODO: assume always?
boolean encoded = containsEncodedParts(uri);
URI requestUrl = UriComponentsBuilder.fromUri(uri)
.host(null)
.port(null)
.uri(this.fallbackUri)
.scheme(null)
.build(encoded)
.toUri();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
ServerHttpRequest request = this.exchange.getRequest().mutate().uri(requestUrl).build();
ServerWebExchange mutated = exchange.mutate().request(request).build();
return RxReactiveStreams.toObservable(getDispatcherHandler().handle(mutated));
public static class Config
private String name;
private Setter setter;
private URI fallbackUri;
public String getName()
return name;
public Config setName(String name)
this.name = name;
return this;
public Config setFallbackUri(String fallbackUri)
if (fallbackUri != null)
setFallbackUri(URI.create(fallbackUri));
return this;
public URI getFallbackUri()
return fallbackUri;
public void setFallbackUri(URI fallbackUri)
if (fallbackUri != null && !"forward".equals(fallbackUri.getScheme()))
throw new IllegalArgumentException("Hystrix Filter currently only supports 'forward' URIs, found " + fallbackUri);
this.fallbackUri = fallbackUri;
public Config setSetter(Setter setter)
this.setter = setter;
return this;
以上是关于Spring Cloud Gateway 使用 HystrixGatewayFilterFactory 熔断降级的主要内容,如果未能解决你的问题,请参考以下文章
聊聊spring cloud gateway的NettyConfiguration
Spring Cloud Gateway 使用谓词检查头部授权
如何配置 spring-cloud-gateway 以使用 sleuth 记录请求/响应正文