【问题标题】:Spring MVC 4: "application/json" Content Type is not being set correctlySpring MVC 4:“application/json”内容类型设置不正确
【发布时间】:2015-08-13 10:56:40
【问题描述】:

我有一个映射有以下注释的控制器:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public String bar() {
    return "{\"test\": \"jsonResponseExample\"}";
}

我返回一个有效的 JSON 字符串,但是,当我在浏览器中查看 Chrome 开发工具上的响应时,内容类型不是 application/json,而只是普通的 text/html。为什么没有设置内容类型?

我的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Spring MVC Web 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>

    <!-- static assets -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

我的dispatcher-servlet.xml

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


    <context:annotation-config />

    <context:component-scan base-package="com.mydomain.controllers" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

使用 WildFly 8.1 作为我的应用服务器。

【问题讨论】:

  • 你是否使用@ResponseBody 并且实际上有一些 Json 映射器?
  • 让我们看看您的方法的其余部分、您的请求标头和完整响应。
  • @SotiriosDelimanolis 全部添加。
  • 为 jackson 添加你的 jackson jar 版本和 springMVC 配置。

标签: java json spring spring-mvc content-type


【解决方案1】:

在控制器的返回类型上使用 jackson 库和 @ResponseBody 注释。

如果您希望返回表示为 JSon 的 POJO,则此方法有效。如果您想返回 String 而不是 POJO 作为 JSon,请参考 Sotirious 答案。

【讨论】:

  • 我确实这样做了,但它仍然不起作用。这可能与我的配置 XML 文件有关吗?使用 Gson 而不是 Jackson,但同样的事情。
  • 请添加更多详细信息,向我们展示您的依赖关系和控制器的完整代码。
  • 我不能谈论这个 Gson,我向你保证杰克逊确实有效。
  • 这可能与 gson 相关:stackoverflow.com/questions/3754055/…,但看起来比开箱即用的杰克逊更努力。
  • 不是配置文件,是Gson的问题。您可以尝试排除它并用杰克逊代替来测试这篇论文吗?
【解决方案2】:

首先要了解的是,RequestMapping#produces() 中的元素

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")

仅用于限制您的请求处理程序的映射。 它什么都不做。

然后,假设您的方法的返回类型为String 并使用@ResponseBody 进行注释,则返回值将由StringHttpMessageConverter 处理,它将Content-type 标头设置为text/plain。如果您想自己返回 JSON 字符串并将标头设置为 application/json,请使用返回类型 ResponseEntity(去掉 @ResponseBody)并向其添加适当的标头。

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<String> bar() {
    final HttpHeaders httpHeaders= new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    return new ResponseEntity<String>("{\"test\": \"jsonResponseExample\"}", httpHeaders, HttpStatus.OK);
}

请注意,您可能应该有

<mvc:annotation-driven /> 

在您的 servlet 上下文配置中使用最合适的默认值设置您的 MVC 配置。

【讨论】:

  • Jackson 库与 @ResponseBody 完美配合
  • @user3360241 带有@ResponseBody 的Jackson 是用MappingJackson2HttpMessageConverter 实现的。它是在StringHttpMessageConverter 之后注册的,因此在处理此请求时没有任何作用。
  • 嗯:mkyong.com/spring-mvc/spring-3-mvc-and-json-example,这也只是示例。我会说操作也希望将自定义对象作为 Json 返回。
  • @user3360241 他们可能想要,但现在他们正在返回String。如果他们确实返回了 POJO,并假设他们的配置是正确的,那么 Jackson 将参与其中。在这种情况下,它不是。
  • 如果您希望将字符串作为内容 json 返回到浏览器,则此答案是正确的,正如您在问题中所指出的那样。如果您应该返回表示为 Json 的 POJO,那么您应该使用一些映射器,例如 Jackson。
【解决方案3】:

正如其他人评论的那样,因为您的方法的返回类型是 String,所以 Spring 不会觉得需要对结果做任何事情。

如果您更改签名以使返回类型成为需要编组的内容,那应该会有所帮助:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Map<String, Object> bar() {
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("test", "jsonRestExample");
    return map;
}

【讨论】:

    【解决方案4】:

    当我升级到 Spring 4 时,我需要更新 jackson 依赖项,如下所示:

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

    【讨论】:

      【解决方案5】:

      我有 @Greg 帖子中指定的依赖项。我仍然面临这个问题,并且可以通过添加以下额外的杰克逊依赖来解决它:

      <dependency>
          <groupId>com.fasterxml.jackson.dataformat</groupId>
          <artifactId>jackson-dataformat-xml</artifactId>
          <version>2.7.4</version>
      </dependency>
      

      【讨论】:

        【解决方案6】:

        不完全针对这个 OP,而是针对那些遇到 404 并且无法将响应 content-type 设置为 "application/json"(任何 content-type)的人。一种可能性是服务器实际响应 406,但资源管理器(例如 chrome)将其打印为 404。

        如果你不自定义消息转换器,spring 会使用AbstractMessageConverterMethodProcessor.java。它会运行:

        List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
        List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
        

        如果它们没有任何重叠(相同的项目),它会抛出HttpMediaTypeNotAcceptableException,这最终会导致406。无论是ajax,还是GET/POST,或者表单动作,如果请求uri以.html 或任何后缀结尾,requestedMediaTypes 将是“text/[that suffix]”,这与producibleMediaTypes 冲突,通常是:

        "application/json"  
        "application/xml"   
        "text/xml"          
        "application/*+xml" 
        "application/json"  
        "application/*+json"
        "application/json"  
        "application/*+json"
        "application/xml"   
        "text/xml"          
        "application/*+xml"
        "application/xml"  
        "text/xml"         
        "application/*+xml"
        

        【讨论】:

        • 如何自定义 AbstractMessageConverterMethodProcessor?
        猜你喜欢
        • 2016-11-17
        • 1970-01-01
        • 2021-07-27
        • 2018-08-06
        • 1970-01-01
        • 2021-01-04
        • 2019-02-20
        • 2017-10-21
        • 1970-01-01
        相关资源
        最近更新 更多