Spring Cloud Gateway - 在过滤器中使用Response body进行不愉快的路径处理(异常处理与Response操作)。

问题描述 投票:0回答:1

用SCG Filter和Response with a body实现不开心路径的管理,最好的(也就是最有效的)方法是什么?异常处理还是响应重写?

场景

我们正在用一些复杂的GatewayFilters(在不同类型的Throttling和其他一些行为之间)实现一个API网关,这些GatewayFilters有一个共同的不快乐路径,它们终止交换链处理,应该立即返回一个具有特定通用体格式的4xx响应(基于Accept头的jsonxml,我们有传统的兼容性要求)。

初步解决方案

我最初的解决方案是使用过滤器,然后尝试用其中的一个选项来写响应。

response.setStatusCode(..);
//set headers
return response.writeAndFlushWith(...);

或者

response.setStatusCode(..);
//set headers
return response.writeWith(...);

甚至

response.setStatusCode(..);
exchange.mutate().response(...);
return response.setComplete();

但主体响应的处理似乎是一个相当啰嗦的过程,再加上由过滤器提供的错误格式化不应该是特定过滤器的关注点,我们希望将关注点分开,所以过滤器应该定义标题、状态和错误信息,但其他人应该将其转化为适当的响应格式。

所以经过长时间的(血腥的:)讨论,我们提出了两个可能的选择。让我们假设我们有4个过滤器,我们的快乐路径将是(近似地不考虑全局过滤器顺序的重叠)。

(initial global filters) -> 1 -> 2 -> 3 -> 4-> 5 -> (other global filters) -> Routing -> (other global filters) -> 5 -> 4-> 3 -> 2 -> 1 -> 0 -> (initial global filters) -> Response

选项1 - 错误处理

实现一个类 java MyErrorHandler extends DefaultErrorWebExceptionHandlerjava MyErrorAttributes extends DefaultErrorAttributes 而这就起到了神奇的作用。

这意味着在特定的过滤器中,抛出一个异常,扩展了 ResponseStatusException 或被注释为 @ResponseStatus 如果我没有说错的话,这样做的好处是可以中断过滤器中所有的交换处理,如果我没有说错的话。... 1 -> 2 -> 3 -> ExH -> (other global filters) -> Response

方案2----对策写作

在最上面的位置添加一个过滤器(过滤器0),也许是一个延伸的过滤器。ModifyResponseGatewayFilter 通过查看特定的 "管理模式 "来管理响应中的错误。交换属性 (例如gateway.error)的bean并写入响应,然后让链中的过滤器设置特定的bean并生成响应。

这将有以下流程。... -> 0 -> 1 -> 2 -> 3 -> 2 -> 1 -> 0 -> (other global filters) -> Response

问题

选项

  1. 方案1似乎是真正阻断处理和建立在现有能力(ExceptionHandler)基础上的短路方案,但我被告知Exceptions是一个可怕的效率负担,因为它们被迫建立所有的stacktrace
  2. 方案2似乎更有效率,但这样一来,响应就会通过所有的 "post "过滤器冒出来,我们必须确保没有其他过滤器试图通过检查特定的 "post "过滤器来更新响应。交换属性 (例如:)gateway.error)

SCG提供的RedisRateLimiter使用了option2,但没有进行正文重写,而是使用了 response.setComplete() 但这不允许以后有任何机构改写。

这是首选的方法吗?

spring-cloud spring-webflux spring-cloud-gateway
1个回答
0
投票

最后我们为了减少不必要的stacktrace创建而去做的是下面的事情。

  1. 我们返回Mono.error(new GatewayRoutingException(...))
  2. 我们将GatewayRoutingException扩展为ResponseStatusException。
  3. 我们覆盖了 fillInStackTrace,所以不会调用原生的 fillInStackTrace(int)

    public synchronized Throwable fillInStackTrace() { return this; }。

  4. 我们将我们想要传递的HttpHeaders和HttpStatus一起存储起来。

  5. 我们重写了ErrorHandler来管理该异常,并返回一个GatewayError bean作为主体,其中包含我们的错误数据结构、http状态和GatewayRoutingException的头信息。
© www.soinside.com 2019 - 2024. All rights reserved.