同步模式下的Spring Webclient拦截器

k4emjkb1  于 2023-11-16  发布在  Spring
关注(0)|答案(1)|浏览(145)

在我们的项目中,我们决定尝试使用spring webclient来请求外部API。但是我们不需要React式方法,所以我们决定在同步模式下使用webclient。我们使用的外部API需要授权,然后在请求的Authorization头中替换一个token。我们编写了一个拦截器,每当调用外部API时,被触发并使用API令牌补充请求。但我们遇到了一个问题,即同一个Web客户端无法在同步模式下的拦截器中使用,因为它给出了一个错误:block()/blockfirst()/blocklast() are blocking, which is not supported in thread parallel-1
在GitHub上发现一个问题:https://github.com/spring-projects/spring-framework/issues/22919但我们没有收到一个明确的理解如何解决这个问题。请告诉我有什么选择来解决这个问题?我的代码示例(这只是一个最小的例子,实际代码更复杂):

@Bean
    public WebClient webClient() {
        .....
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .baseUrl(properties.getBaseUrl())
                .filter(retryRequest())
                .filter(WebclientUtils.exchangeFilterLogRequest())
                .filter(authExchangeFilterFunction())
                .filter(httpStatusErrorHandling())
                .filter(WebclientUtils.exchangeFilterLogResponse())
                .build();

    }

    private ExchangeFilterFunction authExchangeFilterFunction() {
        return (request, next) -> {
                WebClient webClient = WebClient.builder()
                .baseUrl(properties.getBaseUrl())
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .filter(ExchangeFilterFunctions.basicAuthentication(
                                properties.getAuth().getBasic().getUsername(),
                                properties.getAuth().getBasic().getPassword()
                        )
                )
                .filter(WebclientUtils.exchangeFilterLogRequest())
                .filter(WebclientUtils.exchangeFilterLogResponse())
                .build();
                //generate form data
                //.......
                String token = webClient.post()
                            .uri("/oauth/token")
                            .body(BodyInserters.fromFormData(formData))
                            .retrieve()
                            .bodyToMono(String.class)
                            .block();
                next.exchange(ClientRequest.from(request)
                                  .header(HttpHeaders.AUTHORIZATION, token)
                                  .build()))
        }
    }

字符串

5cg8jx4n

5cg8jx4n1#

在这种情况下,你不需要使用block,这与使用不同的操作符链接操作有关,这里是flatMap。此外,重用WebClient示例并避免为每个调用分配这些示例是一个好主意。

public class AuthExchangeFilterFunction implements ExchangeFilterFunction {

    private final WebClient webClient;

    public AuthExchangeFilterFunction(WebClient.Builder builder) {
        this.webClient = builder.build();
    }

    @Override
    public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
        //generate form data
        MultiValueMap<String, String> formData = ...;

        return webClient.post()
                .uri("/oauth/token")
                .body(BodyInserters.fromFormData(formData))
                .retrieve()
                .bodyToMono(String.class)
                .flatMap(token -> {
                    return next.exchange(ClientRequest.from(request)
                            .header(HttpHeaders.AUTHORIZATION, token)
                            .build());
                });
    }

}

字符串

相关问题