欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Cloud Gateway全局通用异常处理的实现

程序员文章站 2024-01-05 20:40:04
为什么需要全局异常处理在传统 spring boot 应用中, 我们 @controlleradvice 来处理全局的异常,进行统一包装返回// 摘至 spring cloud alibaba con...

为什么需要全局异常处理

在传统 spring boot 应用中, 我们 @controlleradvice 来处理全局的异常,进行统一包装返回

// 摘至 spring cloud alibaba console 模块处理
@controlleradvice
public class consoleexceptionhandler {

  @exceptionhandler(accessexception.class)
  private responseentity<string> handleaccessexception(accessexception e) {
    return responseentity.status(httpstatus.forbidden).body(e.geterrmsg());
  }
}

例如: ③ 处应用调用数据库异常,通过 @controlleradvice 包装异常请求响应给客户端

Spring Cloud Gateway全局通用异常处理的实现

但在微服务架构下, 例如 ② 处 网关调用业务微服务失败(转发失败、调用异常、转发失败),在应用设置的 @controlleradvice 将失效,因为流量根本没有转发到应用上处理。

Spring Cloud Gateway全局通用异常处理的实现

如上图: 模拟所有路由断言都不匹配 404 , 和 spring boot 默认保持一致的错误输出页面。 显然我们在网关同样配置 @controlleradvice 是不能解决问题,因为 spring cloud gateway 是基于 webflux 反应式编程。

Spring Cloud Gateway全局通用异常处理的实现

解决方法

默认处理流程

exceptionhandlingwebhandler 作为 spring cloud gateway 最核心 webhandler 的一部分会进行异常处理的过滤

public class exceptionhandlingwebhandler extends webhandlerdecorator {
  @override
  public mono<void> handle(serverwebexchange exchange) {
    mono<void> completion;
    try {
      completion = super.handle(exchange);
    }
    catch (throwable ex) {
      completion = mono.error(ex);
    }

   // 获取全局的 webexceptionhandler 执行
    for (webexceptionhandler handler : this.exceptionhandlers) {
      completion = completion.onerrorresume(ex -> handler.handle(exchange, ex));
    }
    return completion;
  }
}

默认实现 defaulterrorwebexceptionhandler

Spring Cloud Gateway全局通用异常处理的实现

public class defaulterrorwebexceptionhandler {

  @override
  protected routerfunction<serverresponse> getroutingfunction(errorattributes errorattributes) {
   // 根据客户端 `accpet` 请求头决定返回什么资源,如上浏览器返回的是 页面
    return route(acceptstexthtml(), this::rendererrorview).androute(all(), this::rendererrorresponse);
  }
}
// 模拟指定 `accpet` 情况
curl --location --request get 'http://localhost:9999/adminx/xx' \ 18:09:23
   --header 'accept: application/json'
{"timestamp":"2020-05-24 18:09:24","path":"/adminx/xx","status":404,"error":"not found","message":null,"requestid":"083c48e3-2"}⏎

重写 errorwebexceptionhandler

/**
 * @author lengleng
 * @date 2020/5/23
 * <p>
 * 网关异常通用处理器,只作用在webflux 环境下 , 优先级低于 {@link responsestatusexceptionhandler} 执行
 */
@slf4j
@order(-1)
@requiredargsconstructor
public class globalexceptionconfiguration implements errorwebexceptionhandler {
  private final objectmapper objectmapper;

  @override
  public mono<void> handle(serverwebexchange exchange, throwable ex) {
    serverhttpresponse response = exchange.getresponse();

    if (response.iscommitted()) {
      return mono.error(ex);
    }

    // header set
    response.getheaders().setcontenttype(mediatype.application_json);
    if (ex instanceof responsestatusexception) {
      response.setstatuscode(((responsestatusexception) ex).getstatus());
    }

    return response
        .writewith(mono.fromsupplier(() -> {
          databufferfactory bufferfactory = response.bufferfactory();
          try {
            return bufferfactory.wrap(objectmapper.writevalueasbytes(r.failed(ex.getmessage())));
          } catch (jsonprocessingexception e) {
            log.warn("error writing response", ex);
            return bufferfactory.wrap(new byte[0]);
          }
        }));
  }
}

总结

  • 重写的 defaulterrorwebexceptionhandler 优先级一定要小于内置 responsestatusexceptionhandler 经过它处理的获取对应错误类的 响应码
  • 其他扩展 可以参考 sentinelblockexceptionhandler sentinel 整合网关的处理,不过整体和默认的异常处理没有什么区别
  • 基础环境说明:spring cloud hoxton.sr4 & spring boot 2.3.0
  • 具体实现代码参考:

到此这篇关于spring cloud gateway全局通用异常处理的实现的文章就介绍到这了,更多相关spring cloud gateway全局异常内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!