HTTP状态406. Spring MVC 4.0,jQuery,JSON

时间:2014-01-20 13:34:28

标签: java jquery json spring spring-mvc

我想从我的控制器发送JSON。我有以下配置。

spring-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <mvc:annotation-driven/>

    <mvc:resources mapping="/resources/**" location="/resources/"/>
    <context:component-scan base-package="com.castle.controllers"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

.js:

function testAjax() {
    var data = {userName: "MyUsername", password:"Password"};
    $.ajax({
        url: 'ajax/test.htm',
        dataType : 'json',
        type : 'POST',
        contentType: "application/json",
        data: JSON.stringify(data),
        success: function(response){
            alert('Load was performed.');
        }
    });
}

UserTest.java:

public class UserTest {
    private String userName;
    private String password;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

TestAjaxController.java:

@Controller
@RequestMapping("/ajax")
public class TestAjaxController {

    @RequestMapping(method = RequestMethod.POST, value = "/test.htm")
    public @ResponseBody
    UserTest testAjaxRequest(@RequestBody UserTest user) {
        return user;
    }
}

pom.xml:

    <dependency>
                <groupId>org.codehaus.jackson</groupId>
                <artifactId>jackson-mapper-asl</artifactId>
                <version>1.9.13</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.jackson</groupId>
                <artifactId>jackson-core-asl</artifactId>
                <version>1.9.13</version>
</dependency>

当我执行此请求时,我会使用表示为UserTest对象的Controller JSON。但回来时:

HTTP状态406 - 此请求标识的资源只能根据请求“accept”标头生成具有不可接受特征的响应。

我做错了什么?我知道,有很多关于此类案件的问题,但我无法解决它2天......

更新 我找到了解决方案!! 它只需要返回一个Object。不是用户对象或其他东西。 但 return Object;

 public @ResponseBody Object testAjaxRequest(@RequestBody UserTest user) {
        List<UserTest> list = new ArrayList<>();
        list.add(user);
        list.add(user);
        list.add(user);
        return list;

5 个答案:

答案 0 :(得分:20)

这里的主要问题是路径"/test.htm"将在检查Accept标头的值之前首先使用内容协商。使用类似*.htm的扩展名,Spring将使用org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy并确定要返回的可接受媒体类型是text/html,这与MappingJacksonHttpMessageConverter生成的不匹配,即。 application/json因此返回406。

简单的解决方案是将路径更改为/test,其中基于路径的内容协商不会解析响应的任何内容类型。相反,基于标头的不同ContentNegotiationStrategy将解析Accept标头的值。

复杂的解决方案是更改使用ContentNegotiationStrategy注册的RequestResponseBodyMethodProcessor对象的顺序,该@ResponseBody处理您的{{1}}。

答案 1 :(得分:1)

我最后遇到的问题是org.codehaus.jackson 1.9.x的版本, 当我在我的pom.xml中从1.9.x jackson切换到2.x(fasterxml)

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.2.3</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.3</version>

</dependency>

也是必要的:<mvc:annotation-driven />

答案 2 :(得分:1)

在遗留项目中升级Spring时遇到了这个问题。由于后缀,AJAX端点的.html后缀(试图返回JSON)确实被强制用于尝试生成HTML,并且由于处理程序返回了一个对象,因此请求以406错误结束Spring无法弄清楚如何用普通的Java对象制作HTML。

不是更改端点后缀,也不是对自定义ContentNegotiationStrategy进行完整配置,而是进行此更改就足够了:

<mvc:annotation-driven />

更改为:

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

答案 3 :(得分:0)

将这些行添加到上下文配置为我解决了同样的问题:

    <mvc:annotation-driven>
      <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
      </mvc:message-converters>
    </mvc:annotation-driven>

我使用了Spring 4.1.xJackson 2.4.2

答案 4 :(得分:-2)

确保在注释中使用produce =“application / json”。