Spring @RestController不返回纯文本响应

12

我正在尝试使用新的Spring 4.0 @RestController从控制器返回简单的文本响应:

@RestController
@RequestMapping(value = "/heartbeat")
public class HeartbeatController {

    private static final Logger logger = LoggerFactory.getLogger(HeartbeatController.class);

    @RequestMapping
    public String heartbeat() {
        logger.info("Received heartbeat!");
        return "I'm Alive!";
    }

    @RequestMapping(value = "/test", produces = MediaType.TEXT_PLAIN_VALUE)
    public String heartbeat2() {
        logger.info("Received heartbeat!");
        return "I'm Alive!";
    }
}

当我访问/heartbeat时,我得到以下响应:

"I'm Alive!"

结果中包含双引号,这是我没有预料到的。

当我访问/heartbeat/test时,我得到一个空响应,但我期望看到“I'm Alive!”文本。

更新

curl -i http://myserver.com/rest/heartbeat

HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Server: Development/1.0 Date: Tue, 17 Dec 2013 18:59:08 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 12

"I'm Alive!"

curl -i -H "Accept: application/json" http://myserver.com/rest/heartbeat HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Server: Development/1.0 Date: Tue, 17 Dec 2013 19:01:12 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 12

"I'm Alive!"

curl -i http://myserver.com/rest/heartbeat/test

HTTP/1.1 406 Not Acceptable Server: Development/1.0 Date: Tue, 17 Dec 2013 19:00:13 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 0

curl -i -H "Accept: text/plain" http://myserver.com/rest/heartbeat/test

HTTP/1.1 406 Not Acceptable Server: Development/1.0 Date: Tue, 17 Dec 2013 19:02:06 GMT Cache-Control: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Content-Length: 0


2
你是在浏览器中进行还是使用其他HTTP客户端? - Sotirios Delimanolis
1
我不熟悉Spring 4,但是你现在不需要@ResponseBody了吗?我只是好奇。 - marco.eig
使用 Chrome 调试器或 Firebug 发送完整的 HTTP 响应,这样我们可以查看返回代码等信息。 - Angular University
1
@reagten,自Spring 4.0以来,如果您在类上添加RestController而不是Controller,则无需添加ResponseBody。 - Chexpir
5个回答

21
我发现我在WebConfig的configureMessageConverters方法中缺少了StringHttpMessageConverter。 我正在配置消息转换器以控制Jackson ObjectMapper。
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    mappingJackson2HttpMessageConverter.setPrettyPrint(SystemProperty.environment.value() == Development);
    mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper());
    converters.add(mappingJackson2HttpMessageConverter);
    converters.add(new StringHttpMessageConverter()); // THIS WAS MISSING
}

这个问题可能会引起您的兴趣 [SPR-11040](https://jira.springsource.org/browse/SPR-11040) - Brian Clozel
1
谢谢您添加这个,正是我所需要的。 - arcdegree

4

@RestController是一个方便的注解,意味着您不再需要在方法上指定@ResponseBody注解。

但这也意味着您的响应类型被默认设置为JSON,并因此用引号包裹以正确形式呈现。


2
你的意思是 @RestController 只支持 JSON 响应吗?当我添加 products = MediaType.TEXT_PLAIN_VALUE 时,我收到了一个 406。 - Marcel Overdijk
1
您的Curl响应很奇怪,我无法在这里复制。如果请求头与生产者冲突,则heartBeat2()只会返回406状态码。对于引用,请确保在类路径中有Jackson或已注册JSON消息转换器。 - englishteeth

2

@RestController结合了@Controller@ResponseBody,如文档中所述

当您使用@ResponseBody注释方法/控制器时,Spring会使用Accept HTTP请求头和您的注释上的produces属性来协助您进行内容协商。

在您的情况下:

  • 对于心跳操作,您将获得一个application/json响应,因为您的HTTP客户端可能要求该Content-Type,并且Spring已经完成了内容协商。
  • 对于hearthbeat2操作,您将收到HTTP 406错误,因为内容协商失败。您在控制器上指定了text/plain作为生成的Content-Type,而您的HTTP客户端可能只在其Accept请求头中列出application/json

更新:我使用了完全相同的curl请求,但没有获得相同的结果。也许是过滤器或HTTP代理缓存修改了HTTP标头?

默认格式为text/plain:

➜ curl -v http://localhost:8080/heartbeat
> GET /heartbeat HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain;charset=ISO-8859-1
< Content-Length: 13
< Date: Wed, 18 Dec 2013 13:34:12 GMT
<
Hello, World!%

并且使用produces text/plain属性:

➜ curl -H "Accept: text/plain" -v http://localhost:8080/heartbeat/test
> GET /heartbeat/test HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: text/plain
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: text/plain
< Content-Length: 13
< Date: Wed, 18 Dec 2013 13:39:07 GMT
<
Hello, World!%

这个示例应用程序做了相同的事情并获得了良好的结果。


嗨,Brian,感谢你的回答。请看我的示例请求和响应。我认为第一个/heartbeat示例添加引号以将其转换为json...我不明白为什么对于heartbeat/test我会得到406... - Marcel Overdijk
我更新了我的答案,并添加了新的curl测试。当您删除方法上的@RestController并添加@ResponseBody时,您是否有类似的结果? - Brian Clozel
感谢您详尽的回答,非常感激。我发现我缺少了StringHttpMessageConverter。 - Marcel Overdijk

1

这个解决方案对我有效。请检查以下内容。

  1. 确保您的DTO可序列化并具有可序列化的字段、getter和setter。
  2. 检查jackson的依赖项。您应该拥有
    • com.fasterxml.jackson.core:jackson-core:2.4.1
    • com.fasterxml.jackson.core:jackson-databind:2.4.1
    • com.fasterxml.jackson.core:jackson-annotations:2.4.1
    • com.fasterxml.jackson.datatype:jackson-datatype-joda:2.4.1
    • com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.1
  3. 修复RequesMapping注释:

    @RequestMapping(value = "/test", consumes = "*/*")

  4. 检查是否有<mvc:annotation-driven />指令


0
这对我有用:
  1. 在maven中添加以下内容

    com.fasterxml.jackson.core jackson-databind 2.4.4

  2. 确保在Spring中配置了<mvc:annotation-driven />


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接