Spring REST view resolution - unsupported content

2019-08-18 23:13发布

问题:

When posting an XML object Foo to /foo.xml I can't get path extension view resolution to kick in, but get the error

Unsupported content type: text/plain

Which is a result of not posting any Content-Type headers. But favorPathExtention should remove that need. Any idea why it doesn't?


Controller

@RequestMapping(value="/foo.xml", method=ADD, produces="application/xml")
@ResponseStatus(HttpStatus.OK)
public @ResponseBody Foo add(@RequestBody Foo foo)  {
    return foo;
}

Configuration

@Configuration
@ComponentScan(basePackages="my.pkg.controller")
public class RestWebConfig extends WebMvcConfigurationSupport {

    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MarshallingHttpMessageConverter(...));
        converters.add(new MappingJackson2HttpMessageConverter());
    }

    @Override
    protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(true)
            .ignoreAcceptHeader(true)
            .useJaf(false)
            .mediaType("json", MediaType.APPLICATION_JSON)
            .mediaType("xml", MediaType.APPLICATION_XML);
    }
}

回答1:

I think you've misunderstood the purpose of content negotiation.

Content negotiation is for how the response will be generated, not how the request will be parsed.

You get

Unsupported content type: text/plain

because, with @RequestBody, there are no registeredHttpMessageConverter instances that can read the default request content-type of application/octet-stream (or maybe your client uses text/plain). This all happens in the RequestResponseBodyMethodProcessor which handles generating an argument for the parameter annotated with @RequestBody.

If you're going to send XML or JSON in your request body, set the Content-Type.


As for the content negotiation, with your config and request, the DispatcherServlet will attempt to generate a response with content type application/xml. Because of @ResponseBody, you will need an HttpMessageConverter capable of producing such content. Your MarshallingHttpMessageConverter should be enough. If it isn't, you can write your own.



回答2:

I solved the problem by adding text/plain as a supported media type to the message converters, something like

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
    List<MediaType> jsonTypes = new ArrayList<>(jsonConverter.getSupportedMediaTypes());
    jsonTypes.add(MediaType.TEXT_PLAIN);
    jsonConverter.setSupportedMediaTypes(jsonTypes);
    converters.add(jsonConverter);
}