使用 WebClient 将带有标头的请求发送到第三方 api

Posted

技术标签:

【中文标题】使用 WebClient 将带有标头的请求发送到第三方 api【英文标题】:Sending request with headers to third parts api with WebClient 【发布时间】:2019-07-14 01:28:24 【问题描述】:

我真的很喜欢 RestTemplate 的解决方案,但很快它就会随着未来的春季版本而贬值。我正在尝试使用 WebClient 向第三方 api 发送一些文本@

  String text = URLEncoder.encode(text,"UTF-8");

        WebClient webClient = WebClient.builder()
            .baseUrl(BASE_URL)
            .defaultHeader("Key","af999-e99-4456-b556-4ef9947383d")
            .defaultHeader("src", srcLang)
            .defaultHeader("tgt", tgtLang)
            .defaultHeader("text", text)
            .build();

然后在这里发帖:

Mono<String> response = webClient.post().uri("/google/rtv/text")
            .retrieve()
            .bodyToMono(String.class);

尝试根据旧响应进行解析:

private String parseJson( Mono<String> response) 
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = null;
        JsonNode review = null;


        //TODO: create an object and map it here. We need to save the original review too.
        try 
            root = mapper.readTree(response.toString());
            review = root.path("message");

         catch (IOException e) 
            e.printStackTrace();
        

        return review.asText();
    

稍后我需要解析响应,但现在我收到一条错误消息:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'MonoFlatMap': was expecting ('true', 'false' or 'null')
 at [Source: (String)"MonoFlatMap"; line: 1, column: 23]

及以后:

java.lang.NullPointerException: null

我想要完成的事情就像我对 RestTemplate 所做的那样。

像这样:

UriComponentsBuilder builder = UriComponentsBuilder
            .fromUriString(URL)
            .queryParam("src", src)
            .queryParam("tgt", tgt)
            .queryParam("text", text);

ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, request, String.class);

然后全局设置我的订阅标头。

  private ClientHttpResponse intercept(HttpRequest request, byte[] body,
                                         ClientHttpRequestExecution execution) throws IOException 
        request.getHeaders().add("Key","af999-e99-4456-b556-4ef9947383d");
        ClientHttpResponse response = execution.execute(request, body);
        return response;
    

    @Bean
    public RestTemplate restTemplate() 
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList(this::intercept));
        return restTemplate;
    

建议?

【问题讨论】:

从外观上看,Jackson 似乎正在尝试序列化返回的Mono。您能否提供更多关于 Mono 的使用位置以及使用方式的背景信息? 那么Mono&lt;String&gt; 在哪里使用以及如何使用?我这样问是因为问题的根源可能在那里,而不是在您的代码 sn-p 中。 【参考方案1】:

问题发生在这里:

root = mapper.readTree(response.toString());

这段代码 sn-p 试图将 Mono&lt;String&gt; 序列化为字符串,而 Mono 是一种最终可以提供 String 值的反应类型。

你可以调用response.block() 并得到String 的结果,但这将是一个阻塞调用,如果在响应式执行的中间,Reactor 会禁止它。这样做是有充分理由的,因为这会阻塞您的 Web 应用程序正在使用的少数线程之一,并可能导致它停止服务其他请求。

您可以改为:

Mono<String> review = response.map(r -> parseJson(r);

然后重复使用该新值。

请注意,WebClient 本身支持 JSON 反序列化,您可以像这样反序列化整个有效负载:

Mono<Review> review = webClient.post().uri("/google/rtv/text")
        .retrieve()
        .bodyToMono(Review.class);

【讨论】:

以上是关于使用 WebClient 将带有标头的请求发送到第三方 api的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 WebClient 的 spring-security-oauth2 自定义 OAuth2 令牌请求的授权标头?

如何使用 WebClient 反应式 Web 客户端发送带有 zip 正文的 POST 请求

使用 WebClient C# 添加请求标头

WebClient 未向 Windows Phone 中的 Web 服务发送授权标头

如何记录 spring-webflux WebClient 请求 + 响应详细信息(正文、标头、elasped_time)?

使用flash发送带有自定义标头的POST请求