Laurent B
Laurent B

Reputation: 2220

Migration from Spring 3 to Spring 4.1 HTTP Status 406 with Ajax/JSON request

I have migrated my application from Spring 3 to Spring 4.1.7. Now, when i a doing an ajax query, the server responds with an HTTP 406 error.

POST /extranet/EmailIdentificationGetFicheClient.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: application/json, */*; q=0.01
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

The response :

HTTP/1.1 406 Inacceptable Server: Apache-Coyote/1.1 Content-Type: text/html;charset=utf-8 Content-Language: fr Content-Length: 1110 Date: Wed, 26 Aug 2015 08:28:08 GMT

I have the latest jackson librairies in the classpath :

<dependency org="com.fasterxml.jackson.datatype" name="jackson-datatype-json-org" rev="2.6.1" />
<dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.9.13" />

My dispatcher-servlet.xml

<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
    <bean class = "org.springframework.http.converter.StringHttpMessageConverter">
           <property name="supportedMediaTypes" value="text/plain; charset=UTF-8" />
    </bean>    
    <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
            <property name="supportedMediaTypes" value="application/xml"/>
    </bean>
    <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes" value="application/json"/>
    </bean>

</mvc:message-converters>
</mvc:annotation-driven>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
 <property name="favorPathExtension" value="false" />
 <property name="useJaf" value="false" />
 <property name="useNotAcceptableStatusCode" value="false" />
 <property name="viewResolvers">
    <list>
        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
            <property name="order" value="1" />
        </bean>                     
    </list>
</property>
<property name="defaultViews">
    <list>
        <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
    </list>
</property>

As the application lives along with struts, the spring servlet was mapped to *.html URLs.

<servlet>
 <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>

We have several ajax queries such as this one :

$.ajax({
    type : "post",
    accepts : {
      json : 'application/json'
    },
    url : "/extranet/emailIdentification.html",
    cache : false,
    dataType : 'json', ...

The controller code (i can see in debug that it gets correctly there).

@RequestMapping(value="/extranet/EmailIdentification")
@ResponseBody
public Contact getContactFromEmail(HttpServletRequest request) throws SpringException {

Additionnaly, we are using spring-security and what we are trying to do is get spring to recognize the accept header as it did on the previous version.

Thank you for your time.

Upvotes: 0

Views: 627

Answers (2)

Laurent B
Laurent B

Reputation: 2220

I have finally found where my problem was.

The problem was not caused by the jackson librairies for my part as they were correctly loaded.

I noticed in debug that i received an exception HttpMediaTypeNotAcceptableException.

This exception was caused by the ContentNegotiationStrategy loaded was using the path extension instead of the HTTP headers, although i configured the view resolver to ignore path extension :

<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="favorPathExtension" value="false" />
    <property name="useJaf" value="false" />
    <property name="useNotAcceptableStatusCode" value="false" />
    <property name="viewResolvers">

I also added a Content Manager Factory :

<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="useJaf" value="false" />
    <property name="ignoreAcceptHeader" value="false" />
</bean>

But this factory was never taken into account, instead, spring loaded its own version called mvcContentNegotiationManager.

The final hack was therefore to force using the correct class and this is done by setting it through the mvc:annotation-driven tag :

<mvc:annotation-driven content-negotiation-manager="cnManager" />

Et Voilà. Now i can still use the .html extension in spring 4 even for json queries.

Upvotes: 1

MS Ibrahim
MS Ibrahim

Reputation: 1789

The cause of the problem is inability of Spring to load Jackson. It is not loaded by dependencies by default. After I've added the dependency

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.2</version>
  </dependency>

the JSON was returned after typing the address in the browser, without any tricks with Accept headers (as it is supposed to do).

Upvotes: 0

Related Questions