自定义 ZuulFilter抛出异常

前提:
项目中统一使用 HttpResponseCode 来作为服务正常的返回, body 中放具体返回的内容.
如果抛出异常的情况下,期望 code 是4XX,body 中存放错误信息给用户友好提示
但是,在SpringCloud 中默认的异常抛出是一个包含五个字段的对象.如下:

{
    "timestamp": 1513303905953,
    "status": 400,
    "error": "Bad Request",
    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
    "message": "Required Integer parameter 'userId' is not present",
    "path": "/info"
}

我们需要的是这样一种情况的:


接下来我们来实现这种情况.

首先,第一个想到的是使用 @ControllerAdvice 来做全局的异常拦截,对异常进行处理

但是,重启过后并没有什么作用,忽然想到@ControllerAdvice 应该是只处理到达 Controller 中的请求才能被拦截到,而 filter 在 controller 之前,所以拦截不到.那么就要找其他方法来处理.

ZuulFilter 中的 FilterType 中有一个 Error 的处理器.查找这方面资料StackOverflow,别人也遇到过这种情况需要同样的处理.
解决方案如下:

  1. error 类型的 zuulFilter
  2. 执行顺序在默认的 SendErrorFilter (index=0)之前,因此,我们设置为-1
  3. should 方法中检查有没有抛出异常
  4. run 方法中对异常进行处理

代码如下:

@Component
public class ErrorFilter extends ZuulFilter {
    private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);

    @Override
    public String filterType() {
        return "error";
    }

    @Override
    public int filterOrder() {
        //需要在默认的 SendErrorFilter 之前
        return -1; // Needs to run before SendErrorFilter which has filterOrder == 0
    }

    @Override
    public boolean shouldFilter() {
        // only forward to errorPath if it hasn't been forwarded to already
        return RequestContext.getCurrentContext().containsKey("throwable");
    }

    @Override
    public Object run() {
        try {
            RequestContext ctx = RequestContext.getCurrentContext();
            Object e = ctx.get("throwable");

            if (e != null && e instanceof ZuulException) {
                ZuulException zuulException = (ZuulException) e;

                // Remove error code to prevent further error handling in follow up filters
                // 删除该异常信息,不然在下一个过滤器中还会被执行处理
                ctx.remove("throwable");
                // 根据具体的业务逻辑来处理
                ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                 
            }
        } catch (Exception ex) {
            log.error("Exception filtering in custom error filter", ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }
        return null;
    }
}


作者:罗曼蒂克
链接:https://www.jianshu.com/p/2de6290d7bf1
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
### Zuul 全局异常处理方案及最佳实践 #### 1. 使用 `ErrorFilter` 实现全局异常捕获 为了实现 Zuul 的全局异常处理,可以创建自定义的 `ErrorFilter` 来拦截所有未被捕获的异常并统一处理。这种方式能够确保任何抛出到过滤器链之外的异常都能被捕捉。 ```java public class GlobalErrorFilter extends ZuulFilter { @Override public String filterType() { return "error"; } @Override public int filterOrder() { return -1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { Throwable throwable = RequestContext.getCurrentContext().getThrowable(); if (throwable != null) { handleException(throwable); } return null; } private void handleException(Throwable t) { // 自定义的日志记录逻辑 log.error("An unexpected error occurred", t); // 设置响应状态码和消息体给客户端 HttpServletResponse response = RequestContext.getCurrentContext().getResponse(); try { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); } catch (IOException e) { log.warn("Failed to send error message back to client.", e); } } } ``` 此代码片段展示了如何通过继承 `ZuulFilter` 类来构建一个错误类型的过滤器[^1]。 #### 2. 定义 Fallback 方法应对服务降级 当目标微服务不可用时,可以通过 Hystrix 提供的 fallback 机制返回默认的数据或提示信息给前端应用,从而提高系统的容错性和用户体验。 ```yaml hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 5000 ``` 上述 YAML 文件中的设置指定了 Hystrix 命令执行的最大超时时长为五秒;如果超过这个时间,则触发回退逻辑[^2]。 #### 3. 统一管理依赖的服务名称和服务发现配置 为了避免由于拼写错误或其他原因造成的无法找到指定服务的情况发生,在 Spring Cloud 应用程序中应当集中管理和维护对外部资源(如 Eureka 注册中心和其他微服务)的引用关系。 ```properties # application.properties 中的部分内容 eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ zuul.routes.user-service.path=/users/** zuul.routes.user-service.serviceId=user-service ``` 这里给出了两个重要的属性声明:一个是用于连接至 Eureka Server 的 URL 地址,另一个是指定路由规则以及关联的目标服务 ID[^3]。 #### 4. 日志监控与报警集成 对于生产环境下的应用程序而言,完善的日志收集、分析平台不可或缺。借助 ELK Stack 或者其他类似的工具可以帮助运维人员快速定位问题所在,并及时采取措施修复故障。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值