【问题标题】:Webflux, How to intercept a request and add a new headerWebflux,如何拦截请求并添加新标头
【发布时间】:2019-10-15 14:35:00
【问题描述】:

使用Webflux 过滤器,我试图拦截请求并检查请求是否来自某个URI,然后添加一个新的Authorization 标头

过滤器代码简洁明了

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AuthorizationFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

        return chain.filter(Optional.of(exchange)
                .filter(serverWebExchange -> serverWebExchange.getRequest().getURI().getPath().endsWith("/callback"))
                .map(serverWebExchange -> addNewHeader(serverWebExchange))
                .orElse(exchange));
    }

    private ServerWebExchange addNewHeader(ServerWebExchange serverWebExchange) {

        String authHeader=serverWebExchange.getRequest().getQueryParams().get("state").get(0);

        if (authHeader == null) {
            throw new BadRequestException("State not complete (access_token missing) for //callback");
        }

        try {
            serverWebExchange.getRequest().getHeaders().setBearerAuth(authHeader);
        }catch (Throwable t){
            t.printStackTrace();
        }

        return serverWebExchange;
    }
}

但是会抛出异常

java.lang.UnsupportedOperationException
    at org.springframework.http.ReadOnlyHttpHeaders.set(ReadOnlyHttpHeaders.java:99)
    at org.springframework.http.HttpHeaders.setBearerAuth(HttpHeaders.java:774)

标题映射似乎是只读的。我怎样才能克服这个问题并添加新的标题?

【问题讨论】:

    标签: java spring spring-webflux


    【解决方案1】:

    您可以使用 mutate() 方法对 ServerWebExchange 及其 ServerHttpRequest 进行变异,这些方法为每个方法返回一个“Builder”。

    Java 示例:

    @Component
    public class AuthorizationFilter implements WebFilter {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
            ServerHttpRequest mutatedRequest = exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION, "Bearer " + authHeader).build();
            ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
            return chain.filter(mutatedExchange);
        }
    }
    

    示例 Kotlin:

    @Component
    class AuthorizationFilter : WebFilter {
        override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
            val mutatedRequest = exchange.request.mutate().header(HttpHeaders.AUTHORIZATION, "Bearer $authHeader").build()
            val mutatedExchange = exchange.mutate().request(mutatedRequest).build()
            return chain.filter(mutatedExchange)
        }
    }
    

    【讨论】:

    • 奇怪的是.. 我们不需要调用mutate 来修改响应。只需exchange.response.headers.add("x-test-response", "test-value") 即可。
    • 非常感谢这个解决方案!我用它来为响应添加标题,但它仅适用于非错误响应。我通过添加过滤器 bean 的最高顺序解决了这个问题:@Order(Ordered.HIGHEST_PRECEDENCE)
    【解决方案2】:

    由于您在链的map 运算符中添加了一个新标头而导致的问题,在这种情况下,webflux 完成了serverWebExchange 并且它是不可变的。你只需要在调用chain.filter(...)之前添加一个标题。

    【讨论】:

    • 我也是这样做的。但有时,我提到了错误。不知道我错过了什么。出 10-15 次,我用得到一两次这个错误
    • 添加您的代码和错误示例以进行验证
    • 我有一个逻辑错误。反应式编程中相当新的。但你的回答对我来说很有意义。得到了我的错误的答案。
    猜你喜欢
    • 2020-06-23
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 2019-09-19
    相关资源
    最近更新 更多