I recently faced the same issue and found the issue. Thought of sharing it here as it would help others. This behaviour @Patrick explained seems to be occurring due to URL (URL suffix) based content negotiation in Spring MVC.
What is Content Negotiation?
There are situations where we have to deal with multiple representations (or views) of the same data returned by the controller. Working out which data format to return is called Content Negotiation.
How does Content Negotiation Work?
When making a request via HTTP it is possible to specify what type of response you would like by setting the Accept
header property. However, browsers actually send very confusing Accept
headers, which makes relying on them impractical. Therefore Spring offers some alternative conventions for content negotiation.
Spring Content Negotiation Alternatives - URL suffixes and/or a URL Parameter
These work alongside the use of Accept
headers. As a result, the
content-type can be requested in any of three ways. By default they
are checked in this order:
Add a path extension (suffix) in the URL. So, if the incoming URL is something like http://myserver/myapp/accounts/list.html then HTML
is required. For a spreadsheet the URL should be
http://myserver/myapp/accounts/list.xls. The suffix to media-type
mapping is automatically defined via the JavaBeans Activation
Framework or JAF (so activation.jar
must be on the class path).
A URL parameter like this: http://myserver/myapp/accounts/list?format=xls. The name of the
parameter is format by default, but this may be changed. Using a
parameter is disabled by default, but when enabled, it is checked
second.
- Finally the
Accept
HTTP header property is checked. This is how HTTP is actually defined to work, but, as previously mentioned, it can
be problematic to use.
In the above case explained in the question, what you see is path extension based content negotiation in action. (.au)
From the hava doc of ContentNegotiationConfigurer,
favorPathExtension
public ContentNegotiationConfigurer favorPathExtension(boolean
favorPathExtension)
Whether the path extension in the URL path should be used to determine
the requested media type.
By default this is set to true in which case a request for /hotels.pdf
will be interpreted as a request for "application/pdf" regardless of
the 'Accept' header.
The Solution - Setting favorPathExtension to false
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
}
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="parameterName" value="mediaType" />
<property name="ignoreAcceptHeader" value="true"/>
<property name="useJaf" value="false"/>
<property name="defaultContentType" value="application/json" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
</bean>
Please note that above configurations have some additional changes apart from setting favorPathExtension to false.
More details on this can be found here.
Just for completion, the response we get with the issue is as follows.
{
"timestamp": 1518691842254,
"status": 406,
"error": "Not Acceptable",
"exception": "org.springframework.web.HttpMediaTypeNotAcceptableException",
"message": "Not Acceptable",
"path": "/rest/token/something.au"
}