简体   繁体   English

如何使用 Spring WebClient 进行具有不同标头设置的后续调用?

[英]How to use Spring WebClient to make a subsequent call with different header setting?

I need to call an third party API which requires an authentication call beforehand to get an authentication token.我需要调用第三方 API,该 API 需要事先进行身份验证调用才能获取身份验证令牌。 The Authentication API is in json but the subsequent call is in XML.身份验证 API 在 json 中,但后续调用在 XML 中。

I have separately :我分别有:

webclient.post().uri("/auth").header(ACCEPT,JSON).retrieve()
      .bodyToMono(AuthToken.class);
webclient.post().uri("/api").header(ACCEPT,XML).header("AUTH",authToken).retrive().bodyToFlux();

How should I implement the method to be able to access the second API?我应该如何实现能够访问第二个 API 的方法? I tried to assign a variable inside the method with token = firstCall.block() but I've got block() is not supported error.我试图用token = firstCall.block()在方法内分配一个变量,但我有block() is not supported错误。

You just have to transform the original flux like:你只需要像这样转换原始通量:

webclient.post().uri("/auth")
    .header(ACCEPT,JSON)
    .retrieve()
    .bodyToMono(AuthToken.class)
    .flatMapMany(authToken -> webclient.post().uri("/api")
    .header(ACCEPT,XML)
    .header("AUTH",authToken).retrive().bodyToFlux();

A better solution would be to use a ExchangeFilterFunction that will fetch the token for you https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux-client-filter更好的解决方案是使用 ExchangeFilterFunction 为您获取令牌https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux-client-筛选

Something like that (not tested might have bug):类似的东西(未测试可能有错误):

WebClient authWebClient = WebClient.builder().build();
WebClient webClient = WebClient.builder()
        .filter(((request, next) -> authWebClient.post()
                .uri("/auth")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(AuthToken.class)
                .flatMap(authToken -> next.exchange(ClientRequest.from(request)
                        .headers(headers -> headers.add("AUTH", authToken))
                        .build()))
        ))
        .build();

webClient.post().uri("/api")
        .accept(MediaType.APPLICATION_XML)
        .retrieve()
        .bodyToFlux(MyData.class);

This is basic but you could add cache to avoid requesting or fetch again if token is expired... Be aware that builtin ExchangeFilterFunction exists for basic oauth2...这是基本的,但您可以添加缓存以避免在令牌过期时再次请求或获取...请注意,基本的 oauth2 存在内置 ExchangeFilterFunction ...

Wrap everything with a spring configuration:用弹簧配置包裹一切:

@Configuration
public class WebClientConfiguration {
    @Bean
    public WebClient authWebClient(final WebClient.Builder webClientBuilder) {
        return webClientBuilder.build();
    }

    @Bean
    public ExchangeFilterFunction authFilter(final WebClient authWebClient) {
        return (request, next) -> authWebClient.post()
                .uri("/auth")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(AuthToken.class)
                .flatMap(authToken -> next.exchange(ClientRequest.from(request)
                        .headers(headers -> headers.add("AUTH", authToken.toString()))
                        .build()));
    }

    @Bean
    public WebClient webClient(final WebClient.Builder webClientBuilder, final ExchangeFilterFunction authFilter) {
        return webClientBuilder
                .filter(authFilter)
                .build();
    }
}

Or if you want to avoid lambda:或者,如果您想避免使用 lambda:

@Configuration
public class WebClientConfiguration {
@Bean
    public WebClient authWebClient(final WebClient.Builder webClientBuilder) {
        return webClientBuilder.build();
    }

    @Bean
    public WebClient webClient(final WebClient.Builder webClientBuilder, final AuthFilter authFilter) {
        return webClientBuilder
                .filter(authFilter)
                .build();
    }
    
    @Bean
    public AuthFilter authFilter(WebClient authWebClient) {
        return new AuthFilter(authWebClient);
    }
}

public class AuthFilter implements ExchangeFilterFunction {

    private final WebClient authWebClient;

    public AuthFilter(WebClient authWebClient) {
        this.authWebClient = authWebClient;
    }

    @Override
    public Mono<ClientResponse> filter(final ClientRequest request, final ExchangeFunction next) {
        return authWebClient.post()
                .uri("/auth")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(AuthToken.class)
                .flatMap(authToken -> next.exchange(ClientRequest.from(request)
                        .headers(headers -> headers.add("AUTH", authToken.toString()))
                        .build()));
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM