SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(2)

简介: SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(2)

image.png


本系列代码地址: https://github.com/JoJoTec/spring-cloud-parent

我们继续分析上一节提到的 WebHandler,经过将请求封装成 ServerWebExchange 的 HttpWebHandlerAdapter 之后,请求会经过 ExceptionHandlingWebHandler



image.png


全局 Web 处理异常处理器的接入点 - ExceptionHandlingWebHandler


之前有网友私信问过笔者,如何给 Spring Cloud Gateway 加全局异常处理器,其实和给基于 Spring-Flux 的异步 Web 服务加是一样的,都是通过实现并注册一个WebExceptionHandlerBean

WebExceptionHandler.java

public interface WebExceptionHandler {
  Mono<Void> handle(ServerWebExchange exchange, Throwable ex);
}

这些 Bean,就是在 ExceptionHandlingWebHandler 被加入到整个请求处理链路中的:

ExceptionHandlingWebHandler.java

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
  Mono<Void> completion;
  try {
      //这里其实就是组装后面的链路,即调用后面的 FilteringWebHandler 的 handle
    completion = super.handle(exchange);
  }
  catch (Throwable ex) {
    completion = Mono.error(ex);
  }
  for (WebExceptionHandler handler : this.exceptionHandlers) {
    completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
  }
  return completion;
}

从源码可以看出,这里将每个 WebExceptionHandler 作为 Mono 的异常处理 onErrorResume 加入了链路。onErrorResume 的意思是如果链路前面发生异常,则在这里捕获住异常同时调用 handler.handle(exchange, ex) 进行处理,如果使用阻塞代码理解,就相当于:

try {
    //前面的链路
} catch(Throwable ex) {
    return handler.handle(exchange, ex)
}

这里我们看到有多个 WebExceptionHandler,都会在链路后面追加 onErrorResume,其实就相当于:

completion.onErrorResume(ex -> webExceptionHandler1.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler2.handle(exchange, ex)).onErrorResume(ex -> webExceptionHandler3.handle(exchange, ex))...

转换成阻塞代码理解,其实就是:

try {
    completion
} catch(Throwable e1) {
    try {
        return webExceptionHandler1.handle(exchange, e1)
    } catch(Throwable e2) {
        try {
            return webExceptionHandler2.handle(exchange, ex)
        } catch(Throwable e2) {
            return webExceptionHandler3.handle(exchange, ex)
            //如果还有就继续叠加
        }
    }
}

当 WebExceptionHandler 可以处理这个异常的时候,他的 handle 方法会返回一个真正的响应,否则会返回异常,例如:

public class WebExceptionHandler1 implements WebExceptionHandler {
  @Override
  public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
    //如果是 ResponseStatusException 则使用异常里面的响应码和 HTTP 头填充响应的响应码和 HTTP 头
    if (ex instanceof ResponseStatusException) {
      ServerHttpResponse response = exchange.getResponse();
      ResponseStatusException responseStatusException = (ResponseStatusException) ex;
      response.setRawStatusCode(responseStatusException.getRawStatusCode());
      responseStatusException.getResponseHeaders()
          .forEach((name, values) ->
              values.forEach(value -> response.getHeaders().add(name, value)));
      //返回响应完成
      return response.setComplete();
    }
    //抛出异常,继续链路异常处理
    return Mono.error(ex);
  }
}

转换成同步代码去理解其实就是:

if (ex instanceof ResponseStatusException) {
  ServerHttpResponse response = exchange.getResponse();
  ResponseStatusException responseStatusException = (ResponseStatusException) ex;
  response.setRawStatusCode(responseStatusException.getRawStatusCode());
  responseStatusException.getResponseHeaders()
      .forEach((name, values) ->
          values.forEach(value -> response.getHeaders().add(name, value)));
  //返回响应完成
  return response.setComplete();
}
//抛出异常,继续链路异常处理
throw ex;

如果大家想封装自己统一的错误响应,可以通过实现这个接口进行实现。


DefaultWebFilterChain 的链路起点 - FilteringWebHandler


接下来进入 FilteringWebHandler,注意是 org.springframework.web.server.handler.FilteringWebHandler 而不是 Spring Cloud Gateway 的 org.springframework.cloud.gateway.handler.FilteringWebHandler。在这里,会将上下文中载入的 WebFilter 拼接成 DefaultWebFilterChain,然后调用其 filter 方法:

private final DefaultWebFilterChain chain;
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
  super(handler);
  this.chain = new DefaultWebFilterChain(handler, filters);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
  return this.chain.filter(exchange);
}

Spring Cloud Gateway 的 FilteringWebHandler, 它是 Spring Cloud Gateway 的处理请求业务的起点。在这里我们即将进入整个 Spring Cloud Gateway 的 Filter 链路,包括每个路径自己的 GatewayFilter 以及全局的 GlobalGatewayFilter,都是在这里开始被处理组装成完整调用链路的。我们后面还会提到

由于我们的项目依赖中包含了 Spring Cloud Sleuth 以及 Prometheus 的依赖,所以我们这里的 WebFilter 会包括三个:

  • org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter:添加 Prometheus 相关依赖之后,会有这个 MetricsWebFilter,用于记录请求处理耗时,采集相关指标。
  • org.springframework.cloud.sleuth.instrument.web.TraceWebFilter:添加 Spring Cloud Sleuth 相关依赖之后,会有这个 TraceWebFilter。
  • org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter:Spring Cloud Gateway 路由权重相关配置功能相关实现类,这个我们这里不关心。

其具体流程,我们在下一节中继续详细分析。

目录
打赏
0
0
0
0
33
分享
相关文章
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
225 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
AI 时代:从 Spring Cloud Alibaba 到 Spring AI Alibaba
本次分享由阿里云智能集团云原生微服务技术负责人李艳林主讲,主题为“AI时代:从Spring Cloud Alibaba到Spring AI Alibaba”。内容涵盖应用架构演进、AI agent框架发展趋势及Spring AI Alibaba的重磅发布。分享介绍了AI原生架构与传统架构的融合,强调了API优先、事件驱动和AI运维的重要性。同时,详细解析了Spring AI Alibaba的三层抽象设计,包括模型支持、工作流智能体编排及生产可用性构建能力,确保安全合规、高效部署与可观测性。最后,结合实际案例展示了如何利用私域数据优化AI应用,提升业务价值。
328 4
在SpringCloud2023中快速集成SpringCloudGateway网关
本文主要简单介绍SpringCloud2023实战中SpringCoudGateway的搭建。后续的文章将会介绍在微服务中使用熔断Sentinel、鉴权OAuth2、SSO等技术。
212 2
在SpringCloud2023中快速集成SpringCloudGateway网关
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
289 5
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
120 0
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
189 1
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等