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

时间:2019-02-20 11:12:05

标签: spring-boot flux spring-webflux

我真的很喜欢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;
    }

建议?

1 个答案:

答案 0 :(得分:1)

问题发生在这里:

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

Mono<String>是一种可以最终提供该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);