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告訴后端應該返回什么樣的數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM