【问题标题】:Reactive WebClient GET Request with text/html response带有文本/html响应的响应式WebClient GET请求
【发布时间】:2018-07-11 05:12:22
【问题描述】:

目前我遇到了新的 Spring 5 WebClient 的问题,我需要一些帮助来解决它。 问题是:

我请求一些返回内容类型为 text/html;charset=utf-8 的 json 响应的 url。

但不幸的是,我仍然遇到异常: org.springframework.web.reactive.function.UnsupportedMediaTypeException: 不支持内容类型“text/html;charset=utf-8”。所以我不能 将响应转换为 DTO。

对于请求,我使用以下代码:

Flux<SomeDTO> response = WebClient.create("https://someUrl")
                .get()
                .uri("/someUri").accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToFlux(SomeDTO.class);

response.subscribe(System.out::println);

顺便说一句,我在接受标头中指向哪种类型并不重要,总是返回 text/html。那么我怎样才能最终转换我的回复呢?

【问题讨论】:

  • MyClientHttpResponseDecorator(response) - 参数是 ClientHttpResponse,在地图中你得到的是 CLientResponse。这行得通吗?
  • 你找到解决办法了吗?

标签: java spring reactive spring-webflux


【解决方案1】:

如上一个答案所述,您可以使用 exchangeStrategies 方法,

示例:

            Flux<SomeDTO> response = WebClient.builder()
                .baseUrl(url)
                .exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build())
                .build()
                .get()
                .uri(builder.toUriString(), 1L)
                .retrieve()
                .bodyToFlux( // .. business logic


private void acceptedCodecs(ClientCodecConfigurer clientCodecConfigurer) {
    clientCodecConfigurer.customCodecs().encoder(new Jackson2JsonEncoder(new ObjectMapper(), TEXT_HTML));
    clientCodecConfigurer.customCodecs().decoder(new Jackson2JsonDecoder(new ObjectMapper(), TEXT_HTML));
}

【讨论】:

  • 如何初始化 Mime 类型以在此处使用 text/html?
【解决方案2】:

如果您需要设置 maxInMemorySize 以及 text/html 响应,请使用:

  WebClient invoicesWebClient() {
    return WebClient.builder()
        .exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build())
        .build();
  }

  private void acceptedCodecs(ClientCodecConfigurer clientCodecConfigurer) {
    clientCodecConfigurer.defaultCodecs().maxInMemorySize(BUFFER_SIZE_16MB);
    clientCodecConfigurer.customCodecs().registerWithDefaultConfig(new Jackson2JsonDecoder(new ObjectMapper(), TEXT_HTML));
    clientCodecConfigurer.customCodecs().registerWithDefaultConfig(new Jackson2JsonEncoder(new ObjectMapper(), TEXT_HTML));
  }

【讨论】:

    【解决方案3】:

    让服务发送带有"text/html" Content-Type 的 JSON 是相当不寻常的。

    有两种方法可以解决这个问题:

    1. 配置杰克逊解码器也解码"text/html"内容;查看WebClient.builder().exchangeStrategies(ExchangeStrategies)设置方法
    2. 即时更改“Content-Type”响应标头

    这是第二种解决方案的建议:

    WebClient client = WebClient.builder().filter((request, next) -> next.exchange(request)
                    .map(response -> {
                        MyClientHttpResponseDecorator decorated = new 
                            MyClientHttpResponseDecorator(response); 
                        return decorated;
                    })).build();
    
    class MyClientHttpResponseDecorator extends ClientHttpResponseDecorator {
    
      private final HttpHeaders httpHeaders;
    
      public MyClientHttpResponseDecorator(ClientHttpResponse delegate) {
        super(delegate);
        this.httpHeaders = new HttpHeaders(this.getDelegate().getHeaders());
        // mutate the content-type header when necessary
      }
    
      @Override
      public HttpHeaders getHeaders() {
        return this.httpHeaders;
      }
    }
    

    请注意,您应该只在该上下文中使用该客户端(对于该主机)。 如果可以的话,我强烈建议尝试修复服务器返回的奇怪内容类型。

    【讨论】:

    • 第二个选项不起作用。 UnsupportedOperationException尝试修改不可修改的地图你能详细说明你的第一个选项吗?
    • 我已经更新了解决方案 2) 的答案 - 您可以装饰客户端响应以避免该问题。我还指出了更改交换策略的正确构建方法。
    • MyClientHttpResponseDecorator 装饰 = new MyClientHttpResponseDecorator(response);但似乎response 不是 ClientHttpResponse。
    • 第二种解决方案不起作用,因为 Q_SJ 说“响应”似乎不是 ClientHttpResponse。
    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2021-07-21
    • 2021-08-28
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多