3
WebClient.builder().baseUrl("/").filter(contentTypeInterceptor()).build();

How can I modify the Content-Type of the received response (because I'm receiving a response from a webserver that emits the wrong content type. As I'm not in control of the external server, I'd like to correct the content type for further correct processing (eg with jackson library etc).

private ExchangeFilterFunction contentTypeInterceptor() {
    return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
        org.springframework.web.reactive.function.client.ClientResponse.Headers headers = clientResponse.headers();
        //TODO how to headers.setContentType("myval) or headers.set("Content-Type", "myval");   
        //headers.asHttpHeaders(); cannot be used as it is readonly
    });
}

The question could be answered in general how to override any http header.

The root cause in my case is that I receive text/html, but the response body is actually a application/xml. And jackson rejects parsing that response due to:

org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/html' not supported for bodyType=MyResponse

membersound
  • 81,582
  • 193
  • 585
  • 1,120

3 Answers3

4

I had similar issue and the accepted answer didn't work with me. I done this instead, in order to override an invalid content-type that i was receiving.

/**
     * webclient interceptor that overrides the response headers ...
     * */
    private ExchangeFilterFunction contentTypeInterceptor() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> 
            Mono.just(
                    ClientResponse
                        .from(clientResponse) //clientResponse  is immutable, so,we create a clone. but from() only clones headers and status code
                        .headers(headers -> headers.remove(HttpHeaders.CONTENT_TYPE)) //override the content type
                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE) 
                        .body(clientResponse.body(BodyExtractors.toDataBuffers()) ) // copy the body as bytes with no processing
                        .build()));
    }
ahmed galal
  • 109
  • 8
3

Ahmed's response is technically correct. However, I believe that at the time of my posting this, that ClientResponse.from() is deprecated, and you should use the .mutate() method to create a new Builder.

private ExchangeFilterFunction contentTypeInterceptor() {
    return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> 
        Mono.just(clientResponse.mutate()
            .headers(headers -> headers.remove(HttpHeaders.CONTENT_TYPE))
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE)
            .build()));
}
  • Indeed the `.mutate()` was introduced due to an issue of mine regarding my question: https://github.com/spring-projects/spring-framework/issues/24126 , so this is the correct answer nowadays. – membersound Mar 21 '21 at 12:48
1

maybe something like this?

private ExchangeFilterFunction contentTypeInterceptor() {
    return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> 
        Mono.just(ClientRequest.from(clientRequest)
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE)
            .build()));
}
Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • Great, that works. Though I'd be interested in performance drawbacks for creating a new `ClientRequest` object here? – membersound Jul 11 '19 at 14:56
  • well you have no other options since `ClientRequest.class` is an immutable interface https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/ClientRequest.html api docs: `public interface ClientRequest Represents a typed, immutable, client-side HTTP request`. – Toerktumlare Jul 11 '19 at 15:33
  • If that's the only way, I wonder why it has been designed that way... Thank you so far for providing a working solution! – membersound Jul 11 '19 at 18:42
  • 1
    because immutability helps with thread safety. Many threads might touch that object and if you can mutate it it can lead to a lot of problems. My personal opinion is that mutability is bad, really bad because it can lead to very complicated bugs. – Toerktumlare Jul 11 '19 at 19:07
  • As of spring 5.1.9 it will be possible to set different `MimeType` in the `Jaxb2XmlDecoder`: https://github.com/spring-projects/spring-framework/issues/23278 – membersound Jul 13 '19 at 10:43