一文吃透Spring Cloud gateway自定义错误处理Handler

目录
  • 正文
  • AbstractErrorWebExceptionHandler
    • isDisconnectedClientError方法
      • isDisconnectedClientErrorMessage方法:
      • 小结
      • NestedExceptionUtils
    • getRoutingFunction
    • logError
    • write
    • 其他的方法
      • afterPropertiesSet
      • renderDefaultErrorView
      • renderErrorView
  • DefaultErrorWebExceptionHandler
    • getRoutingFunction
      • acceptsTextHtml
      • renderErrorView
    • renderErrorResponse方法
      • getErrorAttributeOptions
  • 自定义自己的异常处理类
    • 继承DefaultErrorWebExceptionHandler
    • 继承AbstractErrorWebExceptionHandler
    • 继承WebExceptionHandler
  • 总结
    • 总体工作流程
    • 得到的经验

正文

我们来学习和了解下GatewayExceptionHandler有助于我们处理spring gateway和webFlux中的异常自定义处理。它继承自ErrorWebExceptionHandler, 类关系图如下:

通过类上述关系图,我们可以看到,DefaultErrorWebExceptionHandlerErrorWebExceptionHandler的实现类,如果我们不自定义类异常处理器,系统将自动装配DefaultErrorWebExceptionHandler

我们就来庖丁解牛,一步步地来学习下这一组类和接口。

AbstractErrorWebExceptionHandler

AbstractErrorWebExceptionHandler实现了ErrorWebExceptionHandler接口,其中handle方法是其核心方法。我们来看下其实现代码:

public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
        // 判断response是否已经提交,并且调用isDisconnectedClientError方法判断是否是客户端断开连接。
        // 如果已经断开连接,已经无法将消息发送给客户端,直接Mono.error(throwable)抛出异常。
        if (!exchange.getResponse().isCommitted() && !this.isDisconnectedClientError(throwable)) {
            // exchange.getAttributes().putIfAbsent(ERROR_INTERNAL_ATTRIBUTE, error);
            this.errorAttributes.storeErrorInformation(throwable, exchange);
            // 创建request
            ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
            return this.getRoutingFunction(this.errorAttributes).route(request).switchIfEmpty(Mono.error(throwable)).flatMap((handler) -> {
                return handler.handle(request);
            }).doOnNext((response) -> {
                this.logError(request, response, throwable);
            }).flatMap((response) -> {
                return this.write(exchange, response);
            });
        } else {
            return Mono.error(throwable);
        }
    }

通过Handle方法的代码我们看出主要是实现了以下的事项:

  • 判断response是否已经提交,并且调用isDisconnectedClientError方法判断是否是客户端断开连接。
  • 如果已经断开连接,已经无法将消息发送给客户端,直接Mono.error(throwable)抛出异常。
  • 将异常信息存储到exchange中。
  • 创建request。
  • 获取路由函数。
  • 调用路由函数的handle方法。
  • 然后执行日志记录。
  • 最后将response写入到exchange中。

isDisconnectedClientError方法

private boolean isDisconnectedClientError(Throwable ex) {
        return DISCONNECTED_CLIENT_EXCEPTIONS.contains(ex.getClass().getSimpleName()) ||this.isDisconnectedClientErrorMessage(NestedExceptionUtils.getMostSpecificCause(ex).getMessage());
}

DISCONNECTED_CLIENT_EXCEPTIONS是一个集合,里面存放了一些异常信息,如果是这些异常信息, 就认为是客户端断开连接了。 或者通过isDisconnectedClientErrorMessage方法判断是否是客户端断开连接的异常信息。

下面我们来看看isDisconnectedClientErrorMessage方法的实现。

isDisconnectedClientErrorMessage方法:

private boolean isDisconnectedClientErrorMessage(String message) {
        message = message != null ? message.toLowerCase() : "";
        return message.contains("broken pipe") || message.contains("connection reset by peer");
}

上述代码的含义是:如果异常信息中包含“broken pipe”或者“connection reset by peer”,就认为是客户端断开连接了。

小结

综合起来,isDisconnectedClientError方法的含义是:如果DISCONNECTED_CLIENT_EXCEPTIONS集合中包含异常信息的类名或者异常信息中包含“broken pipe”或者“connection reset by peer”,就认为是客户端断开连接了。

NestedExceptionUtils

而isDisconnectedClientErrorMessage方法的参数message来自于NestedExceptionUtils.getMostSpecificCause(ex).getMessage()。我们进一步跟踪源码,可以看到NestedExceptionUtils.getMostSpecificCause(ex)方法的源码如下:

public static Throwable getMostSpecificCause(Throwable ex) {
    Throwable cause;
    Throwable result = ex;
    while(null != (cause = result.getCause()) &amp;&amp; (result != cause)) {
        result = cause;
    }
    return result;
}

上述代码的含义是:如果ex.getCause()不为空,并且ex.getCause()不等于ex,就将ex.getCause()赋值给result,然后继续执行while循环。直到ex.getCause()为空或者ex.getCause()等于ex,就返回result。

getRoutingFunction

我们看到获得路由调用的是getRoutingFunction方法,而这个方法是一个抽象方法,需要在具体的继承类中实现。

logError

protected void logError(ServerRequest request, ServerResponse response, Throwable throwable) {
        if (logger.isDebugEnabled()) {
            logger.debug(request.exchange().getLogPrefix() + this.formatError(throwable, request));
        }
        if (HttpStatus.resolve(response.rawStatusCode()) != null && response.statusCode().equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
            logger.error(LogMessage.of(() -> {
                return String.format("%s 500 Server Error for %s", request.exchange().getLogPrefix(), this.formatRequest(request));
            }), throwable);
        }
    }

上述代码的含义:

  • 如果是debug级别的日志,就以debug的方式打印异常信息。
  • 如果response的状态码是500,就打印异常信息。

用到的formatError方法就是简单的讲错误格式化,代码不再一一分析。

write

在把内容写入的时候用到了私有方法write,我们看看write方法的代码如下:

private Mono<? extends Void> write(ServerWebExchange exchange, ServerResponse response) {
        exchange.getResponse().getHeaders().setContentType(response.headers().getContentType());
        return response.writeTo(exchange, new AbstractErrorWebExceptionHandler.ResponseContext());
    }

上述代码的含义是:将response的contentType设置到exchange的response中,然后调用response的writeTo方法,将response写入到exchange中。 ResponseContext是一个内部类,主要是携带了外部类中的viewResolvers和messageWriters属性。

其他的方法

afterPropertiesSet

public void afterPropertiesSet() throws Exception {
        if (CollectionUtils.isEmpty(this.messageWriters)) {
            throw new IllegalArgumentException("Property 'messageWriters' is required");
        }
}

afterPropertiesSet主要是通过实现InitializingBean接口,实现afterPropertiesSet方法,判断messageWriters是否为空,如果为空就抛出异常。

renderDefaultErrorView

protected Mono<ServerResponse> renderDefaultErrorView(BodyBuilder responseBody, Map<String, Object> error) {
        StringBuilder builder = new StringBuilder();
        Date timestamp = (Date)error.get("timestamp");
        Object message = error.get("message");
        Object trace = error.get("trace");
        Object requestId = error.get("requestId");
        builder.append("<html><body><h2>Whitelabel Error Page</h2>").append("<p>This application has no configured error view, so you are seeing this as a fallback.</p>").append("<div id='created'>").append(timestamp).append("</div>").append("<div>[").append(requestId).append("] There was an unexpected error (type=").append(this.htmlEscape(error.get("error"))).append(", status=").append(this.htmlEscape(error.get("status"))).append(").</div>");
        if (message != null) {
            builder.append("<div>").append(this.htmlEscape(message)).append("</div>");
        }
        if (trace != null) {
            builder.append("<div style='white-space:pre-wrap;'>").append(this.htmlEscape(trace)).append("</div>");
        }
        builder.append("</body></html>");
        return responseBody.bodyValue(builder.toString());
    }

renderDefaultErrorView方法主要是渲染默认的错误页面,如果没有自定义的错误页面,就会使用这个方法渲染默认的错误页面。

renderErrorView

protected Mono<ServerResponse> renderErrorView(String viewName, BodyBuilder responseBody, Map<String, Object> error) {
        if (this.isTemplateAvailable(viewName)) {
            return responseBody.render(viewName, error);
        } else {
            Resource resource = this.resolveResource(viewName);
            return resource != null ? responseBody.body(BodyInserters.fromResource(resource)) : Mono.empty();
        }
    }

上述代码的含义是:

  • 如果viewName对应的模板存在,就使用模板渲染错误页面。
  • 否则就使用静态资源渲染错误页面。 在使用资源渲染的时候,调用resolveResource方法,代码如下:
private Resource resolveResource(String viewName) {
        // 获得所有的静态资源的路径
        String[] var2 = this.resources.getStaticLocations();
        int var3 = var2.length;
        // 遍历所有的静态资源
        for(int var4 = 0; var4 < var3; ++var4) {
            String location = var2[var4];
            try {
                // 获得静态资源
                Resource resource = this.applicationContext.getResource(location);
                // 获得静态资源的文件
                resource = resource.createRelative(viewName + ".html");
                if (resource.exists()) {
                    return resource;
                }
            } catch (Exception var7) {
            }
        }
        return null;
    }

DefaultErrorWebExceptionHandler

DefaultErrorWebExceptionHandler是ErrorWebExceptionHandler的默认实现,继承了AbstractErrorWebExceptionHandler。通过对AbstractErrorWebExceptionHandler的分析,我们知道了大致实现原理,下面我们来看看DefaultErrorWebExceptionHandler的具体实现。

getRoutingFunction

在AbstractErrorWebExceptionHandler中,getRoutingFunction方法是一个抽象方法,需要子类实现。DefaultErrorWebExceptionHandler的getRoutingFunction方法的实现如下:

protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(this.acceptsTextHtml(), this::renderErrorView).andRoute(RequestPredicates.all(), this::renderErrorResponse);
}

我们看到代码中调用了RouterFunctions.route和andRoute方法。RouterFunctions.route的作用是根据请求的accept头信息,判断是否是text/html类型,如果是就调用renderErrorView方法,否则就调用renderErrorResponse方法。

acceptsTextHtml

protected RequestPredicate acceptsTextHtml() {
        return (serverRequest) -> {
            try {
                // 获得请求头中的accept信息
                List<MediaType> acceptedMediaTypes = serverRequest.headers().accept();
                // 定义一个MediaType.ALL的MediaType对象
                MediaType var10001 = MediaType.ALL;
                // 移除MediaType.ALL
                acceptedMediaTypes.removeIf(var10001::equalsTypeAndSubtype);
                // 根据类型和权重对MediaType进行排序
                MediaType.sortBySpecificityAndQuality(acceptedMediaTypes);
                // 获得acceptMediaTypes的stream对象
                Stream var10000 = acceptedMediaTypes.stream();
                // 获得MediaType.TEXT_HTML的MediaType对象
                var10001 = MediaType.TEXT_HTML;
                var10001.getClass();
                // 判断是否有MediaType.TEXT_HTML
                return var10000.anyMatch(var10001::isCompatibleWith);
            } catch (InvalidMediaTypeException var2) {
                return false;
            }
        };
    }

acceptsTextHtml方法的作用是判断请求头中的accept信息是否是text/html类型。

renderErrorView

protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
    // 通过getErrorAttributes方法获得错误信息
        Map<String, Object> error = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML));
        // 获得错误状态码
        int errorStatus = this.getHttpStatus(error);
        // 获得错误页面的模板名称
        BodyBuilder responseBody = ServerResponse.status(errorStatus).contentType(TEXT_HTML_UTF8);
        // 获得错误页面的模板名称
        return Flux.just(this.getData(errorStatus).toArray(new String[0])).flatMap((viewName) -> {
            return this.renderErrorView(viewName, responseBody, error);
        }).switchIfEmpty(this.errorProperties.getWhitelabel().isEnabled() ? this.renderDefaultErrorView(responseBody, error) : Mono.error(this.getError(request))).next();
    }

其中

  • this.getData(errorStatus)通过错误的code获得错误页面的名称。
  • this.renderErrorView(viewName, responseBody, error),通过错误页面的名称,错误信息,错误状态码,获得错误页面的响应体。
  • this.renderDefaultErrorView(responseBody, error),通过错误信息,错误状态码,获得默认的错误页面的响应体。

renderErrorResponse方法

protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
    // 通过getErrorAttributes方法获得错误信息
        Map<String, Object> error = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));
        // 获得错误状态码
        // 设置为json格式的响应体
        // 返回错误信息
        return ServerResponse.status(this.getHttpStatus(error)).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(error));
    }

通过上述代码看到主要执行了以下流程:

  • 通过getErrorAttributes方法获得错误信息
  • 获得错误状态码
  • 设置为json格式的响应体
  • 返回错误信息

getErrorAttributeOptions

    protected ErrorAttributeOptions getErrorAttributeOptions(ServerRequest request, MediaType mediaType) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults();
        if (this.errorProperties.isIncludeException()) {
            options = options.including(new Include[]{Include.EXCEPTION});
        }
        if (this.isIncludeStackTrace(request, mediaType)) {
            options = options.including(new Include[]{Include.STACK_TRACE});
        }
        if (this.isIncludeMessage(request, mediaType)) {
            options = options.including(new Include[]{Include.MESSAGE});
        }
        if (this.isIncludeBindingErrors(request, mediaType)) {
            options = options.including(new Include[]{Include.BINDING_ERRORS});
        }
        return options;
    }

我们看到上述代码执行了下面的流程:

  • 获得ErrorAttributeOptions对象
  • 判断是否包含异常信息
  • 判断是否包含堆栈信息
  • 判断是否包含错误信息
  • 判断是否包含绑定错误信息 如果包含这些信息,就将对应的信息加入到ErrorAttributeOptions对象中。而这些判断主要是通过ErrorProperties对象中的配置来判断的。

自定义自己的异常处理类

当认为默认的DefaultErrorWebExceptionHandler不满足需求时,我们可以自定义自己的异常处理类。

继承DefaultErrorWebExceptionHandler

只需要继承DefaultErrorWebExceptionHandler类,然后重写getErrorAttributes方法即可。

import org.springframework.context.annotation.Configuration;
@Configuration
@Order(-1)
public class MyErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
    public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }
    @Override
    protected Map&lt;String, Object&gt; getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Map&lt;String, Object&gt; errorAttributes = super.getErrorAttributes(request, options);
        errorAttributes.put("ext", "自定义异常处理类");
        return errorAttributes;
    }
}

继承AbstractErrorWebExceptionHandler

import org.springframework.context.annotation.Configuration;
@Configuration
@Order(-1)
public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
    public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }
    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(request, options);
        errorAttributes.put("ext", "自定义异常处理类");
        return errorAttributes;
    }
}

继承WebExceptionHandler

import org.springframework.context.annotation.Configuration;
@Configuration
@Order(-1)
public class MyErrorWebExceptionHandler implements WebExceptionHandler {
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(ex);
        } else {
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            return response.writeWith(Mono.just(response.bufferFactory().wrap("自定义异常处理类".getBytes())));
        }
    }
}

总结

总体工作流程

经过对AbstractErrorWebExceptionHandlerDefaultErrorWebExceptionHandler中代码的阅读和跟踪。我们不难看出其工作机制。考虑到有返回API方式的json错误信息和错误页面方式的错误信息。所以ExceptionHandler通过request中的accept的http头进行判断,如果是json格式则以json的方式进行响应,否则则以错误页面的方式进行响应。而错误页面的方式,通过错误的code获得错误页面的名称,然后通过错误页面的名称,错误信息,错误状态码,获得错误页面的响应体。

得到的经验

  • 异步编程和同步编程之间差异很大,特别是在对request和response进行操作的时候。
  • 源代码充分考虑各种情况和细节,在编程中值得我们去做参考。

以上就是一文吃透Spring Cloud gateway自定义错误处理Handler的详细内容,更多关于Spring Cloud gateway Handler的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringCloud启动失败问题汇总

    目录 SpringCloud启动失败问题 Nacos配置读取失败 解决方案 总结 SpringCloud启动失败问题 Nacos配置读取失败 org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1        at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:218) ~

  • springcloud-gateway集成knife4j的示例详解

    目录 springcloud-gateway集成knife4j 环境信息 环境信息 准备工作 网关集成knife4j 编写配置类Knife4jGatewayConfig 测试验证 相关资料 springcloud-gateway集成knife4j 环境信息 环境信息 spring-boot:2.6.3 spring-cloud-alibaba:2021.0.1.0 knife4j-openapi2-spring-boot-starter:4.0.0 准备工作 各微服务&网关引入依赖 <dep

  • SpringCloud开启session共享并存储到Redis的实现

    目录 一.原架构 二.调整架构以及相应的代码 1.Redis和session的配置 2.增加配置类 3.应答过滤器增加session设置 4.增加控制台处理的过滤器ConsoleFilter 5.前端请求中增加(跨域时) 三.部署模式 1.同域 2.跨域 总结 备注:以下所有的gateway均指SpringCloud Gateway 一.原架构 前端<->gateway<->console后端 原来session是在console-access中维护的,当中间有了一层gateway

  • Spring Cloud Ribbon 负载均衡使用策略示例详解

    目录 一.前言 二.什么是 Ribbon 2.1 ribbon简介 2.1.1  ribbon在负载均衡中的角色 2.2 客户端负载均衡 2.3 服务端负载均衡 2.4 常用负载均衡算法 2.4.1 随机算法 2.4.2 轮询算法 2.4.3 加权轮询算法 2.4.4 IP地址hash 2.4.5 最小链接数 三.Ribbon中负载均衡策略总探究 3.1 nacos中使用ribbon过程 3.1.1 添加配置类 3.1.2 接口层调用 3.2 Ribbon中负载均衡配置策略 3.2.1 IRul

  • Spring Cloud Gateway替代zuul作为API网关的方法

    目录 第一,pom文件 第二,项目结构 第三,项目代码和运行截图 运行效果图 参考文档: 本文简要介绍如何使用Spring Cloud Gateway 作为API 网关(不是使用zuul作为网关),关于Spring Cloud Gateway和zuul的性能比较本文不再赘述,基本可以肯定Spring Cloud Finchley版本的gateway比zuul 1.x系列的性能和功能整体要好. 特别提醒:Spring Cloud Finchley版本中,即使你引入了spring-cloud-sta

  • springcloud整合openfeign使用实例详解

    目录 一.前言 二.微服务接口之间的调用问题 2.1 Httpclient 2.2 Okhttp 2.3 HttpURLConnection 2.4 RestTemplate 三.openfeign介绍 3.1 什么是 openfeign 3.2  openfeign优势 四.Spring Cloud Alibaba整合OpenFeign 4.1 前置准备 4.2  完整整合步骤 4.2.1 order模块添加feign依赖 4.2.2  添加feign接口类 4.2.3  调整调用的方法 4.

  • SpringCloud Gateway动态路由配置详解

    目录 路由 动态 路由模型实体类 动态路径配置 路由模型JSON数据 路由 gateway最主要的作用是,提供统一的入口,路由,鉴权,限流,熔断:这里的路由就是请求的转发,根据设定好的某些条件,比如断言,进行转发. 动态 动态的目的是让程序更加可以在运行的过程中兼容更多的业务场景. 涉及到两个服务,一个是门户服务(作用是提供给运营人员管理入口--包括:管理路由.绑定路由),一个是网关服务(gateway组件,为门户服务提供:查询路由信息.添加路由.删除路由.编辑路由接口). 路由模型实体类 /*

  • SpringCloud Gateway路由组件详解

    目录 简介 核心概念 具体示例 GlobalFilter 简介   Gateway是SpringCloud Alibaba中的路由组件(前身是Zuul),作为浏览器端请求的统一入口.当项目采用微服务模式时,若包含了路由模块,浏览器端的请求都不会直接请求含有业务逻辑的各个业务模块,而是请求这个路由模块,然后再由它来转发到各个业务模块去. 核心概念   Gateway中的三个核心概念:路由.断言(Predicate).过滤器.   路由:由唯一id.目的url.断言和过滤组成   断言:即路由规则,

  • SpringCloud修改Feign日志记录级别过程浅析

    目录 前言 1. 介绍 2. 方式一 3. 方式二 前言 本次示例代码的文件结构如下图所示. 1. 介绍 Feign 允许我们自定义配置,下面是 Feign 可以修改的配置. 类型 作用 说明 feign.Logger.Level 修改日志级别 包含四种不同级别:NONE.BASIC.HEADERS.FULL feign.codec.Decoder 响应结果的解析器 HTTP 远程调用的结果做解析,例如解析 JSON 字符串反序列化成 Java 对象 feign.codec.Encoder 请求

  • SpringCloud @RefreshScope刷新机制浅析

    目录 一.前言 二.@Scope 三.RefreshScope 的实现原理 四.总结 一.前言 用过Spring Cloud的同学都知道在使用动态配置刷新的我们要配置一个@RefreshScope 在类上才可以实现对象属性的的动态更新,本着知其所以然的态度,晚上没事儿又把这个点回顾了一下,下面就来简单的说下自己的理解. 总览下,实现@RefreshScope 动态刷新的就需要以下几个: @ Scope @RefreshScope RefreshScope GenericScope Scope C

  • Spring Cloud Alibaba 整合Nacos的详细使用教程

    目录 一.前言 二.常用服务注册中心介绍 2.1 dubbo服务注册示意图 2.2 常用注册中心对比 三.nacos介绍 3.1  什么是nacos 3.2 nacos 特点 3.3 nacos生态链地图 四.nacos部署 4.1 下载安装包 4.2 修改脚本启动模式 4.3  启动nacos 服务 五.Spring Cloud Alibaba 整合Nacos 5.1  Spring Cloud Alibaba版本选型 5.2  实验整合案例说明 5.3  整合完整过程 5.3.1 创建聚合工

  • SpringCloud使用Feign实现远程调用流程详细介绍

    目录 前言 1. 导入依赖坐标 2. 开启Feign自动装配 3. 声明远程调用 4. 替代RestTemplate 5. 测试 前言 本次示例代码的文件结构如下图所示. 1. 导入依赖坐标 在 order-service 的 pom.xml 文件中导入 Feign 的依赖坐标. <!-- Feign远程调用客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifa

  • SpringCloud Hystrix熔断器使用方法介绍

    目录 Hystrix(hi si ju ke si)概述 Hystix 主要功能 隔离 Hystrix 降级 Hystrix降级-服务提供方 初始化程序和Fiegn程序一致 Hystrix降级-服务消费方 provider与Fiegin一致 Hystrix 熔断 Hystrix 熔断监控 Turbine聚合监控 搭建监控模块 修改被监控模块 启动测试 Hystrix(hi si ju ke si)概述 Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务.第三方库,防止

  • SpringCloud @RefreshScope刷新机制深入探究

    目录 梳理过程如下 @RefreshScope ScopedProxyMode RefreshAutoConfiguration NacosConfigService ClientWorker CacheData AbstractSharedListener NacosContextRefresher RefreshEventListener ContextRefresher EventPublishingRunListener RestartListener Java连接nacos后会定时心跳

  • Spring Cloud Gateway远程命令执行漏洞分析(CVE-2022-22947)

    目录 漏洞描述 环境搭建 漏洞复现 声明:本文仅供学习参考,其中涉及的一切资源均来源于网络,请勿用于任何非法行为,否则您将自行承担相应后果,本人不承担任何法律及连带责任. 漏洞描述 使用Spring Cloud Gateway的应用程序在Actuator端点启用.公开和不安全的情况下容易受到代码注入的攻击.攻击者可以恶意创建允许在远程主机上执行任意远程执行的请求. 当攻击者可以访问actuator API时,就可以利用该漏洞执行任意命令. 影响范围 Spring Cloud Gateway <

随机推荐