spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

Append "*/*" To The defaultContentTypes List

Open cgroneman opened this issue 4 years ago • 5 comments

If a default content type is set in the ContentNegotiationConfigurer, endpoints that don't return that type can return a 406. I've attached a very simple example.

demo.zip

Bug Explanation: For an endpoint that produces some other content type (example in attached code is text/plain):

  • Making a request without an Accept header will result in a 406
  • Making a request with an Accept header of '*/*' will result in a 406
  • Making a request with an Accept header of 'garbage/garbage,*/*' will result in 200

This behavior is wrong -- All of these should return a 200. Setting a default content type should not cause endpoints to result in 406. At a minimum, accept headers of 'garbage/garbage,*/*' and '*/*' should behave the same..

Extra explanation Why are we setting a default content type? Because for nearly all endpoints, we want the returned content to be available as XML or JSON, and default to JSON if nothing else is specified.

cgroneman avatar Mar 18 '21 16:03 cgroneman

Indeed the end result from a client perspective doesn't make sense but this is up to your config. It is explicitly mentioned in the Javadoc that what you provide is what is used along with a hint about appending */* at the end:

	 * Set the default content type(s) to use when no content type is requested
	 * in order of priority.
	 * <p>If destinations are present that do not support any of the given media
	 * types, consider appending {@link MediaType#ALL} at the end.

rstoyanchev avatar Mar 19 '21 15:03 rstoyanchev

You're right, and putting MediaType.ALL is what we ended up doing to resolve our issue.

I would suggest that this should be changed for these reasons:

  • It doesn't make sense from the client's perspective
  • It appears to not follow the pattern in the non-javadoc documentation (discussed below)
  • It's not clear to the developer what the problem is.

Before this problem was brought to my attention, the developer who was working on it believed it to be a problem with the headers, because if he commented out .ignoreAcceptHeader(true), it started working in his browser. But that was because his browser was sending a list of accepts, ending with */*.

The documentation at https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html (not sure where that is in the current documentation) makes it sound like headers will be matched before the default content type is used. That's what seems natural as well. A header of '*/*' is not matched (but 'garbage/garbage,*/*' is matched, oddly enough). Needing to put ALL as the last default type feels like a hack. I believe the code should be changed such that no accept header, or '*/*', will match in the scenario I submitted. However, if it is determined that this is working as designed, I request that the documentation be updated to indicate that the default can take precedence over the headers in some situations.

cgroneman avatar Mar 22 '21 13:03 cgroneman

I can improve the documentation to be more explicit about this. A change to the default would have to be in a minor or major version, not a maintenance version.

rstoyanchev avatar Mar 22 '21 16:03 rstoyanchev

@rstoyanchev I stumbled upon this . Is my issue related to above - https://stackoverflow.com/questions/66752245/spring-5-jackson-dataformat-xml-forces-responsebody-with-xml Or how should I fix my issue by configuration. Please let me know

vmisra2018 avatar Mar 23 '21 16:03 vmisra2018

@vmisra2018 I don't think it's related. I've commented on SO.

rstoyanchev avatar Mar 24 '21 17:03 rstoyanchev