[英]Spring MVC 4: “application/json” Content Type is not being set correctly
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/json
but just plain text/html
.但是,我返回了一个有效的 JSON 字符串,当我在浏览器中的 Chrome Dev Tools 上查看响应时,内容类型不是
application/json
而是纯text/html
。 Why is the content type not being set?为什么没有设置内容类型?
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 作为我的应用服务器。
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 String
and is annotated with @ResponseBody
, the return value will be handled by StringHttpMessageConverter
which sets the Content-type
header to text/plain
.然后,假设您的方法具有
String
的返回类型并使用@ResponseBody
注释,则返回值将由StringHttpMessageConverter
处理,后者将Content-type
标头设置为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.如果您想自己返回 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);
}
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 配置。
Use jackson library and @ResponseBody
annotation on return type for the Controller.在控制器的返回类型上使用 jackson 库和
@ResponseBody
注释。
This works if you wish to return POJOs represented as JSon.如果您希望返回表示为 JSon 的 POJO,这将起作用。 If you woud like to return String and not POJOs as JSon please refer to Sotirious answer.
如果您想将字符串而不是 POJO 作为 JSon 返回,请参阅 Sotirious 答案。
As other people have commented, because the return type of your method is String
Spring won't feel need to do anything with the result.正如其他人所评论的那样,因为您的方法的返回类型是
String
Spring 不会觉得需要对结果做任何事情。
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;
}
When I upgraded to Spring 4 I needed to update the jackson dependencies as follows:当我升级到 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>
I had the dependencies as specified @Greg post.我有@Greg 帖子中指定的依赖项。 I still faced the issue and could be able to resolve it by adding following additional jackson dependency:
我仍然面临这个问题,可以通过添加以下额外的 jackson 依赖项来解决它:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.7.4</version>
</dependency>
Not exactly for this OP, but for those who encountered 404 and cannot set response content-type
to "application/json"
(any content-type
).不完全是针对这个 OP,而是针对那些遇到 404 并且无法将响应
content-type
设置为"application/json"
(任何content-type
)的人。 One possibility is a server actually responds 406 but explorer (eg, chrome) prints it as 404.一种可能性是服务器实际上响应 406,但资源管理器(例如,chrome)将其打印为 404。
If you do not customize message converter, spring would use AbstractMessageConverterMethodProcessor.java
.如果不自定义消息转换器,spring 将使用
AbstractMessageConverterMethodProcessor.java
。 It would run:它会运行:
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 HttpMediaTypeNotAcceptableException
and this finally causes 406. No matter if it is an ajax, or GET/POST, or form action, if the request uri ends with a .html
or any suffix, the requestedMediaTypes
would be "text/[that suffix]", and this conflicts with producibleMediaTypes
, which is usually:如果它们没有任何重叠(相同的项目),它会抛出
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"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.