【问题标题】:Spring boot controller content negotiationSpring Boot 控制器内容协商
【发布时间】:2016-01-05 17:29:50
【问题描述】:

我在 Spring-boot 应用程序中编写了一个简单的 REST 控制器,但我不确定如何实现内容协商以使其根据请求标头中的 Content-Type 参数返回 JSON 或 XML。有人可以向我解释一下,我做错了什么吗?

控制器方法:

@RequestMapping(value = "/message", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
  public Message getMessageXML(@RequestParam("text") String text) throws Exception {
    Message message = new Message();
    message.setDate(new Date());
    message.setName("Test");
    message.setAge(99);
    message.setMessage(text);

    return message;
  }

调用此方法时我总是得到 JSON(即使我将 Content-Type 指定为 application/xmltext/xml)。

当我实现两个方法时,每个方法都有不同的映射和不同的内容类型,我可以从 xml 中获取 XML,但是如果我在一个方法中指定两个 mediaTypes(如提供的示例),它将不起作用。

我想要的是调用\message 端点并接收

  • 当 GET 请求的 Content-Type 设置为 application/xml 时的 XML
  • Content-Type 为 application/json 时的 JSON

感谢任何帮助。

编辑: 我更新了我的控制器以接受所有媒体类型

@RequestMapping(value = "/message", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }, consumes = MediaType.ALL_VALUE)
  public Message getMessageXML(@RequestParam("text") String text) throws Exception {
    Message message = new Message();
    message.setDate(new Date());
    message.setName("Vladimir");
    message.setAge(35);
    message.setMessage(text);

    return message;
  }

【问题讨论】:

  • 您需要提供Accept 标头,其值为application/xml 或任何受支持的媒体类型。
  • “Content-Type”标头定义了您发送的内容类型 - 而不是您想要接收的内容(这就是“Accept”标头的用途。所以使用“Content-Type” GET请求的标头没有意义,因为不能有任何(正文)内容。因此,在您的情况下,您应该为您的请求使用“Accept”标头,并在响应中使用“Content-Type”标头来命名实际发送的内容类型。

标签: java rest spring-boot


【解决方案1】:

您可以在博文@RequestMapping with Produces and Consumes 第 6 点找到一些提示。

注意关于 Content-Type 和 Accept headers 的部分:

@RequestMapping 与 Produces 和 Consumes:我们可以使用 header Content-Type 和 Accept 找出请求内容和什么是 它想要响应的 mime 消息。为清楚起见,@RequestMapping 提供生产和消费变量,我们可以在其中指定 请求内容类型将调用哪个方法和响应 内容类型。例如:

@RequestMapping(value="/method6", produces={"application/json","application/xml"}, consumes="text/html")
@ResponseBody
public String method6(){
    return "method6";
}

上述方法只能使用 Content-Type 为 text/html 的消息 并且能够生成 application/json 类型的消息和 应用程序/xml。

您也可以尝试this 不同的方法(使用 ResponseEntity 对象),它可以让您找出传入的消息类型并生成相应的消息(也利用 @ResponseBody 注释)

【讨论】:

    【解决方案2】:

    您可以使用ContentNegotiationConfigurer

    首先,您应该在配置类中覆盖configureContentNegotiation 方法:

    @Configuration
    @EnableWebMvc
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).
                favorParameter(true).
                defaultContentType(MediaType.APPLICATION_JSON).
                mediaType("xml", MediaType.APPLICATION_XML);
        }
    }
    

    favorParameter(true) - 启用优先路径表达式而不是参数或接受标头。

    defaultContentType(MediaType.APPLICATION_JSON) - 设置默认内容类型。这意味着如果您不传递路径表达式,那么 Spring 将生成 JSON 作为响应。

    mediaType("xml", MediaType.APPLICATION_XML) - 设置 XML 的路径表达式键。

    现在如果你像这样声明你的控制器:

    @Controller
    class AccountController {
    
        @RequestMapping(value="/accounts", method=RequestMethod.GET)
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody List<Account> list(Model model, Principal principal) {
            return accountManager.getAccounts(principal) );
        }
    }
    

    并将其命名为 localhost:8080/app/accounts.json,然后 Spring 将生成 JSON 作为响应。因此,如果您致电localhost:8080/app/accounts.xml,您将收到 XML 响应

    您可以找到有关此here 的更多信息。

    【讨论】:

    • 只是对 defaultContentType 的一个小脚注:browsers tend to send accept headers that prefer XML。绕过(假设您没有使用它)Accept 标头可以在您的 contentNegotiation 覆盖中完成:configurer.ignoreAcceptHeader(true)
    • 我认为这里有一个小错误 - 您声称控制器工作的方式,您应该将喜爱路径扩展设置为真,而不是喜爱参数。
    • 另一个小脚注:在 Spring Boot 应用程序中,您的 @Configuration 类应该包含 @EnableWebMvc 注释 (source)。它可能会阻止其他东西工作,例如 springfox-swagger-ui html 页面。
    • 使用 implements WebMvcConfigurer 而不是已弃用的 extends WebMvcConfigurerAdapter 用于当前的 Spring Boot 版本。
    猜你喜欢
    • 2019-03-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    相关资源
    最近更新 更多