Java Spring MVC 4:“application/json”内容类型设置不正确

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30548822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:47:47  来源:igfitidea点击:

Spring MVC 4: "application/json" Content Type is not being set correctly

javajsonspringspring-mvccontent-type

提问by user1757703

I have a controller mapped with the following annotation:

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

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

I return a valid JSON string however, the content-type when I view the response on Chrome Dev Tools in browser is not application/jsonbut just plain text/html. Why is the content type not being set?

但是,我返回了一个有效的 JSON 字符串,当我在浏览器中的 Chrome Dev Tools 上查看响应时,内容类型不仅application/json是普通的text/html. 为什么没有设置内容类型?

My web.xml:

我的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>

My dispatcher-servlet.xml:

我的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>

Using WildFly 8.1 as my app server.

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

采纳答案by Sotirios Delimanolis

First thing to understand is that the RequestMapping#produces()element in

要了解的第一件事是,RequestMapping#produces()在元素

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

serves only to restrict the mapping for your request handlers. It does nothing else.

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

Then, given that your method has a return type of Stringand is annotated with @ResponseBody, the return value will be handled by StringHttpMessageConverterwhich sets the Content-typeheader to text/plain. If you want to return a JSON string yourself and set the header to application/json, use a return type of ResponseEntity(get rid of @ResponseBody) and add appropriate headers to it.

然后,假设您的方法的返回类型为String并用 注释@ResponseBody,则返回值将由将标头StringHttpMessageConverter设置为 的处理。如果您想自己返回一个 JSON 字符串并将标头设置为,请使用(摆脱)的返回类型并向其添加适当的标头。Content-typetext/plainapplication/jsonResponseEntity@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);
}


Note that you should probably have

请注意,您可能应该有

<mvc:annotation-driven /> 

in your servlet context configuration to set up your MVC configuration with the most suitable defaults.

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

回答by John

Use Hymanson library and @ResponseBodyannotation on return type for the Controller.

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

This works if you wish to return POJOs represented as JSon. If you woud like to return String and not POJOs as JSon please refer to Sotirious answer.

如果您希望返回表示为 JSon 的 POJO,这将起作用。如果您想将字符串而不是 POJO 作为 JSon 返回,请参阅 Sotirious 答案。

回答by ninj

As other people have commented, because the return type of your method is StringSpring won't feel need to do anything with the result.

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

If you change your signature so that the return type is something that needs marshalling, that should help:

如果您更改签名以便返回类型需要编组,那应该会有所帮助:

@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;
}

回答by Greg Lindholm

When I upgraded to Spring 4 I needed to update the Hymanson dependencies as follows:

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

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

回答by Vishal

I had the dependencies as specified @Greg post. I still faced the issue and could be able to resolve it by adding following additional Hymanson dependency:

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

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

回答by Tiina

Not exactly for this OP, but for those who encountered 404 and cannot set response content-typeto "application/json"(any content-type). One possibility is a server actually responds 406 but explorer (e.g., chrome) prints it as 404.

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

If you do not customize message converter, spring would use AbstractMessageConverterMethodProcessor.java. It would run:

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

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

and if they do not have any overlapping (the same item), it would throw HttpMediaTypeNotAcceptableExceptionand this finally causes 406. No matter if it is an ajax, or GET/POST, or form action, if the request uri ends with a .htmlor any suffix, the requestedMediaTypeswould be "text/[that suffix]", and this conflicts with producibleMediaTypes, which is usually:

如果它们没有任何重叠(相同的项目),它会抛出HttpMediaTypeNotAcceptableException并最终导致 406。无论是 ajax、GET/POST 还是表单操作,如果请求 uri 以 a.html或任何后缀结尾,这requestedMediaTypes将是“文本/[那个后缀]”,这与 冲突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"