52

我正在尝试生成一个简单的 JSON 响应。现在我收到 406 Not Acceptable 错误。Tomcat 表示“此请求标识的资源只能生成具有根据请求“接受”标头不可接受的特征的响应。即使我的Accept标题是

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

在 tomcat/lib 中,我有所有 Tomcat jar、Spring jar 和 jackson-all-1.9.0.jar。我将 Spring 3.2.2 与 Tomcat 7 一起使用。

我知道这个问题已经讨论过很多次了,但是没有一个解决方案对我有用。

web.xml

<web-app id="WebApp_ID" version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Spring Web MVC Application</display-name>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
        <servlet-class>
                  org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

</web-app>

调度程序-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
 <context:component-scan base-package="com.smiechmateusz.controller" />
 <context:annotation-config />

    <mvc:annotation-driven />

</beans>

HelloWorldController.java

package com.smiechmateusz.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.smiechmateusz.dao.Foo;

@Controller
@RequestMapping("/")
public class HelloWorldController extends AbstractController{

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        ModelAndView model = new ModelAndView("HelloWorldPage");
        return model;
    }

    @RequestMapping(value="foobar.htm", method = RequestMethod.GET)
    public @ResponseBody Foo getShopInJSON() {
        Foo f = new Foo();
        f.setX(1);
        f.setY(2);
        f.setDescription("desc");
        return f;
    }
}

Foo.java

package com.smiechmateusz.dao;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="foobaz")
public class Foo implements Serializable
{
    private int x, y;
    String description;
    int id;

    @Column(name = "x")
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    @Column(name = "y")
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    @Column(name = "description")
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @Id @GeneratedValue
    @Column(name = "id")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

我已经尝试添加

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
          <list>
            <ref bean="jsonConverter"/>
          </list>
    </property>
</bean>

到我的dispatcher-servlet.xml或将jakcson-all更改为jackson-asljackson-core-asl但输出是相同的。

4

22 回答 22

39

如果您使用 Maven 和最新的Jackson 代码,那么您可以从 spring 配置 XML 文件中删除所有 Jackson 特定的配置(您仍然需要一个注释驱动的标签 <mvc:annotation-driven/>)并简单地添加您的 pom.xml 文件的一些 Jackson 依赖项。请参阅下面的依赖项示例。这对我有用,我正在使用:

  • Apache Maven 3.0.4 (r1232337; 2012-01-17 01:44:56-0700)
  • org.springframework 版本 3.1.2.RELEASE
  • 弹簧安全版本 3.1.0.RELEASE。

    ...<dependencies>
    ...
        <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>
        ...
    </dependencies>...
    
于 2013-10-25T15:34:06.220 回答
22

出现此错误的另一种方法是创建一个没有公共成员的类。在这种情况下,406 unacceptable 是一个非常无用的错误消息。

于 2014-04-02T00:55:39.957 回答
19

接受:text/html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8

那应该是问题所在。JSON 用作application/json. 如果您相应地设置 Accept 标头,您应该得到正确的响应。(有一些浏览器插件可以让你设置标题,我最喜欢 Firefox 的“海报”)

于 2013-05-02T11:48:37.297 回答
10

使用 Spring 4,您只需添加@EnableWebMvc,例如:

@Controller
@EnableWebMvc
@RequestMapping(value = "/articles/action", headers="Accept=*/*",  produces="application/json")
public class ArticlesController {

}
于 2015-05-15T17:53:29.820 回答
10

其他答案都没有帮助我。

我阅读了数十个关于 406 Not Acceptable、HttpMediaTypeNotAcceptableException、多部分文件、ResponseBody、设置 Accept 标头、生产、消费等的 Stackoverflow 答案。

我们在 build.gradle 中配置了 SpringBoot 和 Jackson 的 Spring 4.2.4:

compile "com.fasterxml.jackson.core:jackson-core:2.6.7"
compile "com.fasterxml.jackson.core:jackson-databind:2.6.7"

所有路由在我们的其他控制器中都运行良好,我们可以使用 GET、POST、PUT 和 DELETE。然后我开始添加多部分文件上传功能并创建了一个新控制器。GET 路由工作正常,但我们的 POST 和 DELETE 没有。无论我如何从这里尝试不同的解决方案,我都只是不断收到 406 Not Acceptable。

最后我偶然发现了这个答案: Spring throwing HttpMediaTypeNotAcceptableException: 由于 url path 中的点而找不到可接受的表示

阅读 Raniz 的回答和所有评论。

这一切都归结为我们的@RequestMapping 值:

@RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.POST, consumes="multipart/*")
public AudioFileDto insertAudio(@PathVariable String fileName, @RequestParam("audiofile") MultipartFile audiofile) {

    return audioService.insert(fileName, audiofile);
}

@RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.DELETE)
public Boolean deleteAudio(@PathVariable String fileName) {

    return audioService.remove(fileName);
}

在我们的例子中,@RequestMapping 值中的{fileName:.+}部分导致了 406 Not Acceptable。

这是我从 Raniz 的回答中添加的代码:

@Configuration
public class ContentNegotiationConfig extends WebMvcConfigurerAdapter {
    @Override
    void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
        // Turn off suffix-based content negotiation
        configurer.favorPathExtension(false);
    }
}

编辑 2016 年 8 月 29 日:

我们在使用时遇到了麻烦configurer.favorPathExtension(false):静态 SVG 图像停止加载。经过分析,我们发现 Spring 开始将 SVG 文件发送回 UI,内容类型为“application/octet-stream”,而不是“image/svg+xml”。我们通过发送 fileName 作为查询参数来解决这个问题,例如:

@RequestMapping(value = "/audio", method = RequestMethod.DELETE)
public Boolean deleteAudio(@RequestParam String fileName) {

    return audioService.remove(fileName);
}

我们还删除了configurer.favorPathExtension(false). 另一种方法可能是在路径中对 fileName 进行编码,但我们选择了查询参数方法以避免进一步的副作用。

于 2016-07-21T10:21:04.363 回答
7

在你的 pom 中使用以下依赖项

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>
于 2016-04-08T07:27:38.413 回答
5

您必须在 spring-mvc-config.xml 中为 Jackson 注册注解绑定,例如:

<!-- activates annotation driven binding -->
<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" validator="validator">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

然后在您的控制器中,您可以使用:

@RequestMapping(value = "/your_url", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
于 2013-05-02T12:57:30.863 回答
4

我想,问题出在 RequestMapping (foobar.htm)中使用*.htm扩展名。尝试将其更改为footer.json或其他内容。

正确答案的链接:https ://stackoverflow.com/a/21236862/537246

附言

这是Spring默认做某事的方式,关心的是,开发人员从头到尾都知道Spring的整个API。然后只是“406不可接受”没有任何细节,Tomcat的日志是空的!

于 2014-07-10T09:52:47.120 回答
2

看到问题出在扩展名上。根据扩展,spring 可以找出内容类型。如果您的 url 以.com结尾,那么它将text/html作为内容类型标头发送。如果你想改变 Spring 的这种行为,请使用下面的代码:

@Configuration
@Import(HibernateConfig.class)
@EnableWebMvc
// @EnableAsync()
// @EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.azim.web.service.*",  basePackageClasses = { WebSecurityConfig.class }, excludeFilters = { @ComponentScan.Filter(Configuration.class) })
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(name = "validator")
    public Validator validator() {
        return new LocalValidatorFactoryBean();
    }
}

在这里,我们将 favourPathExtension 设置为 false,将 Default Content-type 设置为 Application/json。 注意: HibernateConfig 类包含所有的 bean。

于 2016-04-28T18:49:33.743 回答
2

今天我也遇到了同样的问题。在我的情况下,web.xml我有

   <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

我的网址有.html扩展名。例如:.../getUsers.html。但我在控制器中返回 JSON 数据。.html 扩展名将默认设置接受类型为 html。

所以我改为以下:

网页.xml:

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.json</url-pattern>
</servlet-mapping>

网址:

.../getUsers.json

现在一切正常。希望能帮助到你。

于 2017-03-28T12:06:11.183 回答
1

尝试添加

@RequestMapping(method = RequestMethod.GET,headers = {"Accept=text/xml, application/json"})

getShopInJSON()

它对我有用。

于 2015-04-09T12:07:40.263 回答
1

也许你 POJO 的所有字段都需要 Getter 和 Setter。

我根据这个问题修复了它。参考:Spring MVC - HttpMediaTypeNotAcceptableException

并且 406 不是修复错误的有用消息。您应该调试代码并查看异常到底是什么。

于 2016-04-20T12:09:18.197 回答
1

这是因为对象在 jsp 中是不可接受的......使用他的

将此依赖项或任何其他将转换后的 json 字符串添加到 jsp...

例如在 pom 中添加这个

<dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.6.2</version>
    </dependency>

并使用这样的代码:

@RequestMapping(value="foobar.htm", method = RequestMethod.GET)
    public @ResponseBody String getShopInJSON() {
        Foo f = new Foo();
        f.setX(1);
        f.setY(2);
        f.setDescription("desc");
        return new Gson().toJson(f); //converted object into json string
    }//return converted json string
于 2016-07-28T08:00:42.797 回答
0

看起来您正在尝试生成/接收 json 输出。我发现您的方法存在两个问题。1)您没有在 Accept 标头中指定 application/json 2)您需要在 @RequestMapping 中指定produces="application/json"

于 2015-01-10T11:42:27.727 回答
0

还有另一种情况会返回此状态:如果 Jackson 映射器无法确定如何序列化您的 bean。例如,如果您对同一个布尔属性有两个访问器方法,isFoo()并且getFoo().

删除getFoo()并放置isFoo()。它对我有用。

于 2015-01-28T06:58:10.793 回答
0

我在这里看不到它的答案,所以我想我会提到我在使用 spring 4.2 时收到了这个错误,当时我不小心删除了我期望作为 Json 返回的类的 getter/setter。

于 2015-10-20T09:40:51.193 回答
0

我的RequestMapping价值以.html结尾,应该有所不同。

我尝试将其更改为.json并且对我有用。

于 2016-08-11T10:43:07.180 回答
0

我遇到了类似的问题并通过使用以下代码解决了

public class ProductList {

    private List<Product> productList =  new ArrayList<Product>();

    @JsonProperty("data")
    @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
    public List<Product> getProductList() {
        return productList;
    }
public void setProductList(List<Product> productList) {
        this.productList = productList;
    }

I am setting ProductList object in ResponseEntity object and returning from controller.
于 2016-09-13T20:09:17.910 回答
0

我的类使用 JsonSerialize 进行了注释,并且 include 参数设置为JsonSerialize.Inclusion.NON_DEFAULT. 这导致 Jackson 确定每个 bean 属性的默认值。我有一个返回 int 的 bean 属性。我的问题是 bean getter 调用了一个具有推断返回类型的方法(即:泛型方法)。出于某种奇怪的原因,这段代码被编译了;它不应该编译,因为您不能将 int 用于推断的返回类型。我将该 bean 属性的“int”更改为“Integer”,但不再得到 406。奇怪的是,如果我将 Integer 更改回 int,则代码现在无法编译。

于 2017-10-26T18:43:23.903 回答
0

由于这是此错误的最佳答案,因此我在此处添加 XML 案例。

返回的对象也有可能没有正确定义 XML 结构。我就是这样。

public @ResponseBody DataObject getData(

尽管标题正确,但仍抛出相同的错误。当我将 @XmlRootElement 添加到对象的标头时,错误停止了:

@XmlRootElement
public class DataObject {
    @XmlElement(name = "field", nillable = true)
    protected String field;
于 2020-05-08T08:28:52.240 回答
0

我有同样的问题,在我的情况下,我的 xxx-servlet.xml 配置文件中缺少以下内容

<mvc:annotation-driven/>

我一添加它,它就起作用了。

于 2020-06-10T18:25:37.083 回答
0

我遇到了同样的“406”错误,但根本原因与Spring的对象=> json策略有关...

春天:3.2.2.RELEASE

雄猫:7

@RequestMapping(value = "/employee/search/v2/{employeeId}")
    public ResponseEntity<EmployeeProfileResponseData> searchEmployeeV2(@PathVariable String employeeId) 

EmployeeProfileResponseData.java 段


    private Boolean profileActive;

    public Boolean isProfileActive() {
        return this.profileActive;
    }

    public Boolean getProfileActive() {
        return this.profileActive;
    }

    public void setProfileActive(Boolean profileActive) {
        this.profileActive = profileActive;
    }

如果可怜的 POJO 包含公共方法isProfileActive,它总是会返回 406。

但是如果我删除了该方法,它会返回正常的 JSON。

所以我尝试将方法重命名为isMyProfileActive,然后我发现返回的 JSON 包含一个新属性:

{
    ...
    "profileActive": true,
    "myProfileActive": true
}

然后我意识到发生了什么。

当 POJO 包含公共方法isProfileActive时,Spring 会相应地生成一个属性“profileActive”。但是,JSON 已经包含同名的属性(根据公共 getter/setter 方法)。所以这两个属性引起了冲突,Tomcat 不会返回正常的 JSON。

这正是“406”代码的含义。

超文本传输​​协议 (HTTP) 406 Not Acceptable 客户端错误响应代码表示服务器无法生成与请求的主动内容协商标头中定义的可接受值列表匹配的响应,并且服务器不愿意提供默认表示。

所以最后我删除了这个isProfileActive方法,一切都很好。

BTW,该isProfileActive方法是由vscode生成的,我的同事推送了该代码而没有太在意。

于 2021-11-04T08:24:20.297 回答