zoukankan      html  css  js  c++  java
  • RequestMapping中consumes 和produces的作用

    环境与参考资料

    环境:spring 5.2.1 release,springboot 2.2.1.RELEASE
    参考资料:HTTP 响应代码 - HTTP _ MDN

    源码

    先看源码

    /**
    	 * Narrows the primary mapping by media types that can be consumed by the
    	 * mapped handler. Consists of one or more media types one of which must
    	 * match to the request {@code Content-Type} header. Examples:
    	 * <pre class="code">
    	 * consumes = "text/plain"
    	 * consumes = {"text/plain", "application/*"}
    	 * consumes = MediaType.TEXT_PLAIN_VALUE
    	 * </pre>
    	 * Expressions can be negated by using the "!" operator, as in
    	 * "!text/plain", which matches all requests with a {@code Content-Type}
    	 * other than "text/plain".
    	 * <p><b>Supported at the type level as well as at the method level!</b>
    	 * If specified at both levels, the method level consumes condition overrides
    	 * the type level condition.
    	 * @see org.springframework.http.MediaType
    	 * @see javax.servlet.http.HttpServletRequest#getContentType()
    	 */
    	String[] consumes() default {};
    
    	/**
    	 * Narrows the primary mapping by media types that can be produced by the
    	 * mapped handler. Consists of one or more media types one of which must
    	 * be chosen via content negotiation against the "acceptable" media types
    	 * of the request. Typically those are extracted from the {@code "Accept"}
    	 * header but may be derived from query parameters, or other. Examples:
    	 * <pre class="code">
    	 * produces = "text/plain"
    	 * produces = {"text/plain", "application/*"}
    	 * produces = MediaType.TEXT_PLAIN_VALUE
    	 * produces = "text/plain;charset=UTF-8"
    	 * </pre>
    	 * <p>If a declared media type contains a parameter (e.g. "charset=UTF-8",
    	 * "type=feed", type="entry") and if a compatible media type from the request
    	 * has that parameter too, then the parameter values must match. Otherwise
    	 * if the media type from the request does not contain the parameter, it is
    	 * assumed the client accepts any value.
    	 * <p>Expressions can be negated by using the "!" operator, as in "!text/plain",
    	 * which matches all requests with a {@code Accept} other than "text/plain".
    	 * <p><b>Supported at the type level as well as at the method level!</b>
    	 * If specified at both levels, the method level produces condition overrides
    	 * the type level condition.
    	 * @see org.springframework.http.MediaType
    	 * @see org.springframework.http.MediaType
    	 */
    	String[] produces() default {};
    

    源码中主要是这两句话
    consumer:Narrows the primary mapping by media types that can be consumed by the mapped handler.
    produces: Narrows the primary mapping by media types that can be produced by the mapped handler.

    这两者都是和MediaType相关,而MediaType让我想到了 http协议request header中 content-type 和 Accept 字段的值。

    consumer 和 produces 翻译就是消费者和生产者。这让我联想到生产者消费者模型,Http请求也是一个IO流的操作,肯定有输入和输出了,consumer和produces用在某个方法上时,应该指的就是该方法只能处理 consumer类型的input,produces类型的output了。

    那么 这些字段相互的作用应该是这样的

    • 如果 request header的content-type和方法中的consumer不匹配的话,那么该方法将无法处理。
    • 如果 request header的accept和方法中的produces不匹配的话,那么该方法将无法处理。

    Demo

    处理方法

    @PostMapping(value = "/hello",consumes = {"application/json"},produces = {"application/xml"})
    @ResponseBody
    public User hello(@RequestBody User user) {
          System.out.println(user);
          return user;
    }
    

    User类

    import lombok.Data;
    
    @Data
    public class User {
        private String name;
        private Integer age;
    }
    

    request content-type为 application/x-www-form-urlencoded,accept不设置

    后台无打印
    response status 406
    此情况是读取input数据就有问题了。

    request content-type为 application/json,accept为不设置

    request body

    {
        "name":"2",
        "age":"1"
    
    }
    

    后台打印 User{name='2', age=1}
    response status 406
    response body

    {
        "timestamp": "2020-12-18T03:43:35.664+0000",
        "status": 406,
        "error": "Not Acceptable",
        "message": "Could not find acceptable representation",
        "path": "/hello"
    }
    

    此情况是读取input数据没有问题,写output出现问题。

    request content-type为 application/json,accept为application/xml

    request body

    {
        "name":"2",
        "age":"1"
    
    }
    

    后台打印 User{name='2', age=1}
    response status 406
    response body 为空

    此情况是读取input数据没有问题,写output出现问题。

    解决方法

    在UserBean 添加XmlRootElement注解。

    import lombok.Data;
    import javax.xml.bind.annotation.XmlRootElement;
    @Data
    @XmlRootElement
    public class User {
        private String name;
        private Integer age;
    }
    

    再次请求
    response status 200
    response body

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <user>
        <age>1</age>
        <name>2</name>
    </user>
    

    hello方法删除produces

    request header为 application/json的请求返回json数据。
    request header为 application/xml的请求返回xml数据。

    总结

    后端使用consumers和produces来指定当前方法处理 content-type和accept为什么的请求,前端使用accept告诉后端应该返回什么样的数据。

  • 相关阅读:
    【465】词干提取与词形还原
    【464】文本转字符向量bag of words
    【462】淘宝个人简介
    Docker 图形化页面管理工具使用
    Docker 简介与shell操作使用
    Spring Boot 入门案例与配置说明
    项目管理工具Maven的安装与使用
    Git(五)IDEA应用Git
    Git(四)Git的分支管理
    Git(三)Git的远程仓库
  • 原文地址:https://www.cnblogs.com/alway-july/p/14154230.html
Copyright © 2011-2022 走看看