【问题标题】:Spring Cloud GlobalFilter: Resend modified request on failureSpring Cloud GlobalFilter:失败时重新发送修改的请求
【发布时间】:2021-05-21 18:30:44
【问题描述】:

我们使用带有 GlobalFilter 的 Spring Cloud Gateway 来处理对请求的令牌注入。这是过滤器的代码:

@Override
public Mono<Void> filter(final ServerWebExchange exchange, final GatewayFilterChain chain) {
    log.info("We received a request");

    exchange.getRequest().mutate()
            .headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));

    return chain.filter(exchange);
}

tokenService.getToken()-方法从缓存中返回一个令牌,如果缓存中尚不存在,则从后端返回一个新令牌。但是可能会导致令牌在后端失效。如果再次使用令牌发出请求,后端会以 401 响应。在这种情况下,我们希望拦截响应,使缓存无效,从后端请求新令牌(之后再次缓存)并重新发送请求使用新令牌。此外,还设置了一个标头,指示已重试请求以避免无限循环。 这应该对客户透明地发生。

以下是关于所需数据流的简短说明:

到目前为止我已经尝试过的:

@Override
public Mono<Void> filter(final ServerWebExchange exchange, final GatewayFilterChain chain) {
    log.info("We received a request");

    exchange.getRequest().mutate()
            .headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));

    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        final ServerHttpResponse response = exchange.getResponse();
        if (response.getStatusCode().is4xxClientError()) {
            log.error("We got a 4xx");
            if (!exchange.getRequest().getHeaders().containsKey("X-retries")) {
                log.info("Trying to resend request");
                exchange.getRequest().mutate()
                        .headers(h -> h.add("X-retries", "1"));
                tokenService.evictCache();
                exchange.getRequest().mutate()
                        .headers(h -> h.remove("Authorization"))
                        .headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
                chain.filter(exchange);
            } else {
                log.info("Retry failed");
            }
        }
    }));
}

但我在后端日志中看不到第二个请求。

如何将修改后的请求再次发送到后端?

【问题讨论】:

    标签: spring cloud gateway reactor webflux


    【解决方案1】:

    我想错误出在代码部分:

     exchange.getRequest().mutate()
                .headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
    

    它不会改变现有的exchange,它会创建一个新的。因此,您需要保存指向变异对象的链接,例如:

    ServerWebExchange newExchange = exchange.getRequest().mutate()
                .headers(h -> h.add("Authorization", String.format("Bearer %s", tokenService.getToken())));
    

    之后,newExchange 必须在您的代码中使用

    【讨论】:

    • 来自ServerHttpRequest.Builder mutate() 的官方文档:“[...] 返回变异值或委托回此实例。”我确实可以在到达后端服务的请求中看到添加的 Authorization 标头。不工作的是在执行第二个chain.filter 时接收第二个请求。我认为此时必须有回报。但是Mono.then() 是不可能的
    猜你喜欢
    • 2020-11-09
    • 2012-02-11
    • 2015-08-31
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 2020-06-20
    相关资源
    最近更新 更多