拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 自定义Zuul 异常

自定义Zuul 异常

白鹭 - 2022-03-07 2205 0 2

一、概述

Zuul 是Netflix 的基于JVM 的路由器和服务器端负载均衡器Zuul 的规则引擎提供了编写规则和过滤器的灵活性,以增强Spring Cloud 微服务架构中的路由。

在本文中,我们将通过编写自定义错误过滤器来探索如何在Zuul 中自定义异常和错误响应,这些过滤器会在代码执行期间发生错误时运行

2. Zuul 异常

Zuul 中所有处理的异常都是ZuulExceptions现在,让我们明确一点,ZuulException不能被@ControllerAdvice捕获并通过@ExceptionHandling注释方法这是因为** ZuulException**是从错误过滤器中抛出的因此,它会跳过后续的过滤器链,并且永远不会到达错误控制器。下图描述了Zuul 中错误处理的层次结构:

customizing-zuul-exceptions.png

当出现ZuulException时,Zuul 显示如下错误响应:

{
 "timestamp": "2022-01-23T22:43:43.126+00:00",
 "status": 500,
 "error": "Internal Server Error"
 }

在某些场景下,我们可能需要在ZuulException.Zuul 过滤器来救援。在下一节中,我们将讨论如何扩展Zuul 的错误过滤器和自定义ZuulException.

3. 自定义Zuul 异常

spring-cloud-starter-netflix-zuul的入门包包括三种类型的过滤器:前置、后置和错误过滤器。在这里,我们将深入了解错误过滤器并探索名为SendErrorFilter的Zuul 错误过滤器的自定义

首先,我们将禁用自动配置的默认SendErrorFilter这使我们不必担心执行顺序,因为这是唯一的Zuul 默认错误过滤器。让我们在application.yml中添加属性来禁用它:

zuul:
 SendErrorFilter:
 post:
 disable: true

现在,让我们编写一个名为CustomZuulErrorFilter的自定义Zuul 错误过滤器,如果底层服务不可用,它会抛出自定义异常:

public class CustomZuulErrorFilter extends ZuulFilter {
 }

这个自定义过滤器需要扩展com.netflix.zuul.ZuulFilter并覆盖它的一些方法`.`

首先,我们必须重写filterType()方法并将类型作为“error”返回这是因为我们要为错误过滤器类型配置Zuul 过滤器:

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

之后,我们覆盖filterOrder()并返回-1,因此过滤器是链中的第一个

@Override
 public int filterOrder() {
 return -1;
 }

然后,我们重写shouldFilter()方法并无条件返回true,因为我们希望在所有情况下都链接此过滤器:

@Override
 public boolean shouldFilter() {
 return true;
 }

最后,让我们重写run()方法

@Override
 public Object run() {
 RequestContext context = RequestContext.getCurrentContext();
 Throwable throwable = context.getThrowable();
 if (throwable instanceof ZuulException) {
 ZuulException zuulException = (ZuulException) throwable;
 if (throwable.getCause().getCause().getCause() instanceof ConnectException) {
 context.remove("throwable");
 context.setResponseBody(RESPONSE_BODY);
 context.getResponse()
 .setContentType("application/json");
 context.setResponseStatusCode(503);
 }
 }
 return null;
 }

让我们分解这个run()方法以了解它在做什么。首先,我们获取RequestContext的实例。接下来,我们验证从RequestContext获得的throwable是否是ZuulException的实例。然后,我们检查throwable中嵌套异常的原因是否是ConnectException的实例。最后,我们使用响应的自定义属性设置了上下文。

请注意,在设置自定义响应之前,我们会从上下文中清除throwable,以防止在后续过滤器中进行进一步的错误处理

此外,我们还可以在run()方法中设置一个自定义异常,该异常可以由后续过滤器处理:

if (throwable.getCause().getCause().getCause() instanceof ConnectException) {
 ZuulException customException = new ZuulException("", 503, "Service Unavailable");
 context.setThrowable(customException);
 }

上面的代码片段将记录堆栈跟踪并继续执行下一个过滤器。

此外,我们可以修改这个例子来处理ZuulFilter.

4. 测试自定义Zuul 异常

在本节中,我们将在CustomZuulErrorFilter中测试自定义Zuul 异常。

假设有一个ConnectException,上述示例在Zuul API 的响应中的输出将是:

{
 "timestamp": "2022-01-23T23:10:25.584791Z",
 "status": 503,
 "error": "Service Unavailable"
 }

此外,**我们始终error.path /error**在application.yml文件中配置error.path 属性来更改默认的Zuul 错误转发路径/error。

现在,让我们通过一些测试用例来验证它:

@Test
 public void whenSendRequestWithCustomErrorFilter_thenCustomError() {
 Response response = RestAssured.get("http://localhost:8080/foos/1");
 assertEquals(503, response.getStatusCode());
 }

在上面的测试场景中,/foos/1的路由被故意保留下来,导致java.lang. ConnectException结果,我们的自定义过滤器将拦截并响应503 状态。

现在,让我们在不注册自定义错误过滤器的情况下进行测试:

@Test
 public void whenSendRequestWithoutCustomErrorFilter_thenError() {
 Response response = RestAssured.get("http://localhost:8080/foos/1");
 assertEquals(500, response.getStatusCode());
 }

在不注册自定义错误过滤器的情况下执行上述测试用例会导致Zuul 响应状态为500。

5. 结论

在本教程中,我们了解了错误处理的层次结构,并深入研究了在Spring Zuul 应用程序中配置自定义Zuul 错误过滤器。此错误过滤器提供了自定义响应正文和响应代码的机会。


标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *