如何在Spring Rest Controller中动态设置响应内容类型?

Kri*_*ish 4 rest spring spring-mvc

我已经实现了一个 API,它将根据客户端的请求(即请求中的 Accept 标头)返回 JSON 和 XML。它按预期工作。

这里的问题是:即使用户发送 Accept 标头,在某些特殊情况(即业务逻辑)下,我们需要动态发送响应内容类型。我尝试使用 HttpHeaders 来实现它,但它不起作用。

@GetMapping
public ResponseEntity<Response> getQueries(){
...............

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    //headers.add("Content-Type", "application/json");  
    return new ResponseEntity<Response>(response, headers, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)

我收到的 HTTP 状态为 200,但响应为错误,即

Unexpected '<'
Run Code Online (Sandbox Code Playgroud)

如何解决这个问题?

sof*_*ake 8

您的问题是关于内容协商的,它是一种允许消费者(您的用户代理)和提供者(您的控制器)从一开始就响应的媒体类型达成一致的功能

首先,由 APi 使用者来指示它将接受什么媒体类型作为响应。这是通过将 Accept 标头设置为所需类型来完成的。因此,在消费者期望响应类型为 JSON 的情况下,Accept 标头应该配置为 XML 的“application/json”或“application/xml”(或每个的任何特定变体,例如“application/xhtml+xml”和一样)。

在控制器端,您需要使用“ Produces ”注释属性指定支持的响应媒体类型。还有同级“consumes”属性,用于指定支持的请求媒体类型。Sooo...我们的映射应该如下所示:

@GetMapping(value="someEndpoint",
        produces={"application/json","application/xml"})
public ResponseEntity<Page<Person>> getPersons(
        @RequestParam(value = "page", required = true) Integer pPage,
        @RequestParam(value = "size", required = true) Integer pSize) 
{
    Page<Person>  result;
    result = personService.getPersons(new PageRequest(pPage, pSize));
    return new ResponseEntity<>(result, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)

现在有趣的部分是,您不必担心响应格式,因为 Spring 将能够根据 http 请求 Accept 标头的值检测消费者所需的响应媒体类型。

更好的是,通过正确的配置,如果请求中没有 Accept 标头,您可以设置默认响应媒体类型。因此,通过将默认响应内容类型设置为“application/json”,任何没有 Accept 标头的请求都将以 JSON 形式提供服务,而消费者必须添加 Accept:“application/xml”才能将响应类型设置为 xml。

有关此主题和配置设置的示例和变体,请参阅此Spring 指南。

希望这可以帮助,

杰克