spring-boot: @RequestMapping Content-Type error when a @RequestBody is used but Content-Type header is not given
We are trying to upgrade to 1.3.0.M1 from 1.2.1. When using the 1.2.1 version, we did not have to set the Content-Type: application/json header when sending a request body to a method web service endpoint like:
@RequestMapping(value = "filter", method = RequestMethod.POST)
List<StateData> filter(@RequestBody StateData filter) {
}
The Content-Type would be With version 1.3.0.M1, the call will fail when passing a @RequestBody if the Content-Type header is not set, with the error:
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported at
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:216) at
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:148) at
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:126) at
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) at
org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162) at
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129) at
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111) at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:799) at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:728) at
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) at
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
... 67 more
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 24 (11 by maintainers)
Commits related to this issue
- Repro test for SPR-12778 behavior change See spring-projects/spring-boot#3313 Issue: SPR-12778 — committed to bclozel/spring-framework by bclozel 9 years ago
- Fix @RequestBody argument processing for null Content-Type Since the changes introduced in SPR-12778, some `@RequestBody` args would not be properly processed in some cases: * requests with an empty... — committed to bclozel/spring-framework by bclozel 9 years ago
for my case the headers must be :
Content-Type: application/json and i solve the problem good luck
Hi @lewisdavidcole
Could you give more details about this issue please? Especially, HTTP headers for request and response. In any case, what you’re describing here looks normal -
application/octet-streamis a sensible default for"Content-Type"if none is sent by the client. What HTTP client are you using?I’ve just reproduced this exact behavior in Spring Boot 1.2.1, with the following:
Maybe do you have a custom
ContentNegotiationStrategythat sets thedefaultContentType? I don’t think Boot is doing anything like this.Thanks for looking deeper into the behavior. I think there is one aspect missing: The input to the controller method is marked as optional:
There are 2 important parts to the method signature:
There is nothing special about the SampleData object, but note that all my code is in Groovy:
I created these in a separate sample project to remove any inadvertent configuration or code that would affect the outcome. If you are interested, here is my build.gradle file (using 3.0.0M1):
Using the sample project and only cURL instead of PostMan, you ca see the results and URL’s used at the bottom of the post.
Summary
The results are pretty clear, there is an obvious change in behavior, which I think has degraded.
Version 1.2.1
GET requests don’t accept a response body, so the Content-Type is never required. POST requests - ONLY if data is set on the request body is the Content-Type needed.
Version 3.0.0M1
GET requests where the controller method has an optional @RequestBody requires the Content-Type to be set, whether or not the data is set on the request body. Note that in the example Controller method, the method supports both GET and POST requests, with the @RequestBody’s required attribute set false.
POST requests - The Content-Type is always required whether the request body is set or not.
I believe the way version 1.2.1 functions is the correct behavior. Because the @RequestBody can be an optional parameter, the Content-Type should not be required if the request body is not set, regardless of the request type.
Just for fyi… we have the filter endpoint to support both GET and POST requests because we allow the filter to be called without criteria as a GET to retrieve all results possible.
cURL Results
Spring Boot 1.3.0.M1
GET request with Content-Type set
curl -X GET -H “Content-Type: application/json” http://localhost:8080/TestApp/sample/filter
GET request with no Content-Type set
curl -v -X GET http://localhost:8080/TestApp/sample/filter
POST with no Content-Type and no request body
curl -v -X POST http://localhost:8080/TestApp/sample/filter
POST with no Content-Type and a request body
curl --data “{"sampleString1":"test"}” -v -X POST "http://localhost:8080/TestApp/sample/filter
POST with Content-Type set and no request body
curl -v -X POST -H “Content-Type: application/json” http://localhost:8080/TestApp/sample/filter
POST with Content-Type set and a request body
curl --data “{"sampleString1":"test"}” -v -X POST -H “Content-Type: application/json” “http://localhost:8080/TestApp/sample/filter”
Spring Boot 1.2.1
GET request with Content-Type set
curl -v -X GET -H “Content-Type: application/json” http://localhost:8080/TestApp/sample/filter
GET request with no Content-Type set
curl -v -X GET http://localhost:8080/TestApp/sample/filter
POST with no Content-Type and no request body
curl -v -X POST http://localhost:8080/TestApp/sample/filter
POST with no Content-Type and a request body
curl --data “{"sampleString1":"test"}” -v -X POST “http://localhost:8080/TestApp/sample/filter”
POST with Content-Type set and no request body
curl -v -X POST -H “Content-Type: application/json” http://localhost:8080/TestApp/sample/filter
POST with Content-Type set and a request body
curl --data “{"sampleString1":"test"}” -v -X POST -H “Content-Type: application/json” “http://localhost:8080/TestApp/sample/filter”
I met the same problem. Did you solve it? How did you solve it?
hello
specify
@JsonPropertyin entity class constructor like this.It’s not a Content-Type header check but rather a failure to find a suitable
HttpMessageConverter. TheStringHttpMessageConvertercan deal with “text/plain” but it only converts to String. TheJacksonHttpMessageConvertercan convert toSNSMessagebut it only gets involved forapplication/json. You could configure theJacksonHttpMessageConverterto also converttext/plainbut that could cause you issues in other endpoints. I do not see what we could do in Spring MVC to make this better. We are in a worse position to make assumptions.Probably the simplest reliable thing to do is to insert the request body as a String and invoke the Jackson converter manually. This is just a weird situation to begin with. Another option might be to use a custom
ContentNegotiationStrategythat resolves the content type for very specific URLs. Then you can keep your method signature as it is.