理解 RESTful API 面向資源 冪等性
如何理解RESTful的冪等性
我來答
分享
舉報瀏覽 3612 次
1個回答
#再見,2018!# 2018要結束了,你還有哪些心願沒完成??
最佳答案
熱心網友
2017-07-02
等冪性(Idempotence)
等冪性簡單點說就是一次請求和多次請求,資源的狀態是一樣。比如GET和HEAD,不論你請求多少次,資源還是在那裡。請注意,DELETE和PUT也是等冪的,以為對同一個資源刪除一次或者多次,結果是一樣的,就是資源被刪除了,不存在了。為什麼說PUT也是等冪的?當你PUT一個新資源的時候,資源被建立,再次PUT這個URI的時候,資源還是沒變。當你PUT一個存在的資源時,更新了資源,再次PUT的時候,還是更新成這個樣子。在PUT更新的時候,不能做相對的更新(依賴資源現在的狀態),比如每次對一個數加1,這樣資源狀態就會變化。應該每次更新成某個數,比如把某個數變成4,則無論多少次PUT,值都是4,這樣就是等冪了。
我們設計Restful WS的時候,GET,HEAD, PUT, DELETE一定要設計成等冪的。由於網路是不可靠的,安全性和等冪性就顯得特別重要。如果一次請求,伺服器收到處理以後,客戶端沒有收到相應,客戶端會再次請求,如果沒有等冪性保障,就會發生意想不到的問題。
POST是不安全也不等冪的,還是拿weblog的例子,如果兩次POST相同的博文,則會產生兩個資源,URI可能是這樣/weblogs/myweblog/entries/1和/weblogs/myweblog/entries/2,儘管他們的內容是一摸一樣的。
https://zhidao.baidu.com/question/373737226952238764.html
隨筆- 63 文章- 0 評論- 25
RESTful 個人理解總結
一.什麼是RESTful 面向資源
簡單的說:RESTful是一種架構的規範與約束、原則,符合這種規範的架構就是RESTful架構。
先看REST是什麼意思,英文Representational state transfer 表述性狀態轉移 其實就是對 資源 的表述性狀態轉移。
資源的地址 在web中就是URL (統一資源識別符號)
資源是REST系統的核心概念。 所有的設計都是以資源為中心
結合專案怎麼識別資源
1.商品加入購物車 購物車
2.提交訂單 訂單
3.建立使用者 使用者
圍繞資源進行 新增,獲取,修改,刪除,以及對符合特定條件的資源進行列表操作 。針對資源設計介面
二.關於規範與約束有哪些?
RESTful 架構的核心規範與約束:統一介面
分為四個子約束:
1.每個資源都擁有一個資源標識,每個資源的資源標識可以用來唯一地標明該資源
2.訊息的自描述性
3.資源的自描述性。
4.HATEOAS Hypermedia As The Engine Of Application State(超媒體作為應用狀態引擎)
即客戶只可以通過服務端所返回各結果中所包含的資訊來得到下一步操作所需要的資訊,如到底是向哪個URL傳送請求等。也就是說,一個典型的REST服務不需要額外的文件標示通過哪些URL訪問特定型別的資源,而是通過服務端返回的響應來標示到底能在該資源上執行什麼樣的操作
目的:實現客戶端無需藉助任何文件即能呼叫到所有的伺服器資源
三、資源的URL設計
1.通過URL來表示資源
資源分為主資源與子資源
因為主資源是一類獨立的資源 所以主資源應直接放在相對路徑下:例如
若要表示主資源的例項:如果例項的ID=1,則這樣表示: /goods/1
子資源:
一個例項的子資源可能是一個集合也可能是一個單一的子資源
子資源為圖片集合:/goods/1/pictures
子資源為商品折扣的單子子資源:/goods/1/discount
2.單數 vs. 複數
獲取使用者1的資訊,哪種方式更符合RESTful?
/api/users/1
/api/user/1
3.相對路徑 vs. 請求引數
極光的RESTful API:
獲取使用者資訊 GET /v1/users/{username} 引數放在路徑中
VS
獲取使用者資訊 GET /v1/users?username=xxxxx 拼接的方式
獲取應用管理員列表 GET /v1/admins?start={start}&count={count} ?後拼接引數的方式:這種方式一般作為過濾資源
4.使用合適的動詞 get delete put post
選擇請求介面的方式: get delete
PUT 在伺服器更新資源(客戶端提供改變後的完整資源)。
POST 在伺服器新建一個資源
5.使用標準的狀態碼
GET
- 安全且冪等
- 獲取表示
- 變更時獲取表示(快取)
- 200(OK) - 表示已在響應中發出
- 204(無內容) - 資源有空表示
- 301(Moved Permanently) - 資源的URI已被更新
- 303(See Other) - 其他(如,負載均衡)
- 304(not modified)- 資源未更改(快取)
- 400 (bad request)- 指代壞請求(如,引數錯誤)
- 404 (not found)- 資源不存在
- 406 (not acceptable)- 服務端不支援所需表示
- 500 (internal server error)- 通用錯誤響應
- 503 (Service Unavailable)- 服務端當前無法處理請求
-
POST
- 不安全且不冪等
- 使用服務端管理的(自動產生)的例項號建立資源
- 建立子資源
- 部分更新資源
- 如果沒有被修改,則不過更新資源(樂觀鎖)
- 200(OK)- 如果現有資源已被更改
- 201(created)- 如果新資源被建立
- 202(accepted)- 已接受處理請求但尚未完成(非同步處理)
- 301(Moved Permanently)- 資源的URI被更新
- 303(See Other)- 其他(如,負載均衡)
- 400(bad request)- 指代壞請求
- 404 (not found)- 資源不存在
- 406 (not acceptable)- 服務端不支援所需表示
- 409 (conflict)- 通用衝突
- 412 (Precondition Failed)- 前置條件失敗(如執行條件更新時的衝突)
- 415 (unsupported media type)- 接受到的表示不受支援
- 500 (internal server error)- 通用錯誤響應
- 503 (Service Unavailable)- 服務當前無法處理請求
PUT
- 不安全但冪等
- 用客戶端管理的例項號建立一個資源
- 通過替換的方式更新資源
- 如果未被修改,則更新資源(樂觀鎖)
- 200 (OK)- 如果已存在資源被更改
- 201 (created)- 如果新資源被建立
- 301(Moved Permanently)- 資源的URI已更改
- 303 (See Other)- 其他(如,負載均衡)
- 400 (bad request)- 指代壞請求
- 404 (not found)- 資源不存在
- 406 (not acceptable)- 服務端不支援所需表示
- 409 (conflict)- 通用衝突
- 412 (Precondition Failed)- 前置條件失敗(如執行條件更新時的衝突)
- 415 (unsupported media type)- 接受到的表示不受支援
- 500 (internal server error)- 通用錯誤響應
- 503 (Service Unavailable)- 服務當前無法處理請求
DELETE
- 不安全但冪等
- 刪除資源
- 200 (OK)- 資源已被刪除
- 301 (Moved Permanently)- 資源的URI已更改
- 303 (See Other)- 其他,如負載均衡
- 400 (bad request)- 指代壞請求
- 404 (not found)- 資源不存在
- 409 (conflict)- 通用衝突
- 500 (internal server error)- 通用錯誤響應
- 503 (Service Unavailable)- 服務端當前無法處理請求
-
6.選擇適當的表示結構
json xml
7. 版本控制
例如:
hello world!!!
http://www.cnblogs.com/wang-yaz/p/9237981.html
如何理解RESTful的冪等性
2017年02月18日 23:31:57 garfielder007 閱讀數:5554
理解RESTful的冪等性,並且設計符合冪等規範的高質量RESTful API。
怎麼理解冪等性
HTTP冪等方法,是指無論呼叫多少次都不會有不同結果的 HTTP 方法。不管你呼叫一次,還是呼叫一百次,一千次,結果都是相同的。
還是以之前的博文的例子為例。
-
GET /tickets # 獲取ticket列表
-
GET /tickets/12 # 檢視某個具體的ticket
-
POST /tickets # 新建一個ticket
-
PUT /tickets/12 # 更新ticket 12
-
PATCH /tickets/12 # 更新ticket 12
-
DELETE /tickets/12 # 刪除ticekt 12
HTTP GET方法
HTTP GET方法,用於獲取資源,不管呼叫多少次介面,結果都不會改變,所以是冪等的。
-
GET /tickets # 獲取ticket列表
-
GET /tickets/12 # 檢視某個具體的ticket
只是查詢資料,不會影響到資源的變化,因此我們認為它冪等。
值得注意,冪等性指的是作用於結果而非資源本身。怎麼理解呢?例如,這個HTTP GET方法可能會每次得到不同的返回內容,但並不影響資源。
可能你會問有這種情況麼?當然有咯。例如,我們有一個介面獲取當前時間,我們就應該設計成
GET /service_time # 獲取伺服器當前時間
它本身不會對資源本身產生影響,因此滿足冪等性。
HTTP POST方法
HTTP POST方法是一個非冪等方法,因為呼叫多次,都將產生新的資源。
POST /tickets # 新建一個ticket
因為它會對資源本身產生影響,每次呼叫都會有新的資源產生,因此不滿足冪等性。
HTTP PUT方法
HTTP PUT方法是不是冪等的呢?我們來看下
PUT /tickets/12 # 更新ticket 12
因為它直接把實體部分的資料替換到伺服器的資源,我們多次呼叫它,只會產生一次影響,但是有相同結果的 HTTP 方法,所以滿足冪等性。
HTTP PATCH方法
HTTP PATCH方法是非冪等的。HTTP POST方法和HTTP PUT方法可能比較好理解,但是HTTP PATCH方法只是更新部分資源,怎麼是非冪等的呢?
因為,PATCH提供的實體則需要根據程式或其它協議的定義,解析後在伺服器上執行,以此來修改伺服器上的資源。換句話說,PATCH請求是會執行某個程式的,如果重複提交,程式可能執行多次,對伺服器上的資源就可能造成額外的影響,這就可以解釋它為什麼是非冪等的了。
可能你還不能理解這點。我們舉個例子
PATCH /tickets/12 # 更新ticket 12
此時,我們服務端對方法的處理是,當呼叫一次方法,更新部分欄位,將這條ticket記錄的操作記錄加一,這次,每次呼叫的資源是不是變了呢,所以它是有可能是非冪等的操作。
HTTP DELETE方法
HTTP DELETE方法用於刪除資源,會將資源刪除。
DELETE /tickets/12 # 刪除ticekt 12
呼叫一次和多次對資源產生影響是相同的,所以也滿足冪等性。
如何設計符合冪等性的高質量RESTful API
HTTP GET方法 vs HTTP POST方法
也許,你會想起一個面試題。HTTP請求的GET與POST方式有什麼區別?你可能會回答到:GET方式通過URL提交資料,資料在URL中可以看到;POST方式,資料放置在HTML HEADER內提交。但是,我們現在從RESTful的資源角度來看待問題,HTTP GET方法是冪等的,所以它適合作為查詢操作,HTTP POST方法是非冪等的,所以用來表示新增操作。
但是,也有例外,我們有的時候可能需要把查詢方法改造成HTTP POST方法。比如,超長(1k)的GET URL使用POST方法來替代,因為GET受到URL長度的限制。雖然,它不符合冪等性,但是它是一種折中的方案。
HTTP POST方法 vs HTTP PUT方法
對於HTTP POST方法和TTP PUT方法,我們一般的理解是POST表示建立資源,PUT表示更新資源。當然,這個是正確的理解。
但是,實際上,兩個方法都用於建立資源,更為本質的差別是在冪等性。HTTP POST方法是非冪等,所以用來表示建立資源,HTTP PUT方法是冪等的,因此表示更新資源更加貼切。
HTTP PUT方法 vs HTTP PATCH方法
此時,你看會有另外一個問題。HTTP PUT方法和HTTP PATCH方法,都是用來表述更新資源,它們之間有什麼區別呢?我們一般的理解是PUT表示更新全部資源,PATCH表示更新部分資源。首先,這個是我們遵守的第一準則。根據上面的描述,PATCH方法是非冪等的,因此我們在設計我們服務端的RESTful API的時候,也需要考慮。如果,我們想要明確的告訴呼叫者我們的資源是冪等的,我的設計更傾向於使用HTTP PUT方法。
from:http://blog.720ui.com/2016/restful_idempotent/
http://www.tuicool.com/articles/E7zeeii
https://blog.csdn.net/garfielder007/article/details/55684420
RESTful API 最佳實踐
使用者2214491發表於java一日一條訂閱
119
在這篇文章中:
- 1. URI
- 2. Request:通過標準HTTP方法對資源CRUD
- 3. Response
- 4. API版本控制
- 5. 速度限制
- 6.快取
- 7.覆蓋HTTP方法
- 8.過濾資訊
- 10.HTTP狀態碼
- 11.認證
- 12.使用SSL
- 13.Hypermedia API
在參考了GitHub API設計和大量部落格文章後總結了一下RESTful API的設計,分享如下。想要更好的理解RESTful API首先需要理解如下概念:
REST:REST(Representational State Transfer)這個詞,是Roy Thomas Fielding在他2000年的博士論文中提出的,翻譯成中文大意為表現層狀態傳輸。由於他是HTTP協議(1.0版和1.1版)的主要設計者、Apache伺服器軟體的作者之一、Apache基金會的第一任主席,所以REST原則迅速流行起來。當一個軟體架構符合REST原則,我們稱之為RESTful架構。說了這麼多,我們為什麼要使用RESTful架構?使用RESTful架構有什麼好處?因為按照RESTful架構可以充分的利用HTTP協議帶給我們的各種功能,算是對HTTP協議使用的最佳實踐,還有一點就是可以使軟體架構設計更加清晰,可維護性更好,但是並不是所有情況都需要完全遵守REST原則,畢竟實際情況遠遠比REST原則所定義的更加複雜,下面會詳細介紹。
冪等性:冪等性(Idempotence)本身是一個數學概念,在HTTP/1.1規範中冪等性的定義是:
Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
翻譯過來大意就是如果方法呼叫一次和多次產生額外的效果是相同的,它就具有冪等性。
例子:在HTTP中使用GET方法通常用於從伺服器獲取資源,無論呼叫多少次產生的額外效果都是從伺服器獲取資源,所以GET具有冪等性;而POST方法通常用於提交資料在伺服器上建立一個資源,由於最終建立的結果每次都是不同的,所以POST不具有冪等性;但是PUT方法卻是冪等的,因為每次呼叫產生的效果都是對資源進行更新。
安全方法:安全方法是指不修改資源的 HTTP 方法。譬如,當使用 GET 或者 HEAD 作為資源 URL,都必須不去改變資源。然而,這並不全準確。意思是:它不改變資源的 表示形式。對於安全方法,它仍然可能改變伺服器上的內容或資源,但這必須不導致不同的表現形式。
有關HTTP常用方法冪等性和安全性如下:
RESTful API設計規則:
1. URI
- 應該將API部署在專用域名之下:https://api.example.com
- 不用大寫
- 用中槓-不用下槓_;
- 引數列表要encode;
- URI中不應該出現動詞,動詞應該使用HTTP方法表示,但是如果無法表示,也可使用動詞,例如:search沒有對應的HTTP方法,可以在路徑中使用search,更加直觀;
- URI中的名詞表示資源集合,使用複數形式;
- 雖然/在URI中表達層級,但是避免為了追求REST導致層級過深,適當使用引數表示。 GET /comments/tid/tid=1&page=1
2. Request:通過標準HTTP方法對資源CRUD
- GET:查詢資源 GET /comments //獲取所有評論 GET /comments/tid/1 //獲取文章tid為1的所有評論
- POST:建立資源 POST /comments/tid/1 //為tid為1的文章建立評論
- PUT:更新資源 PUT /comments/cid/like/1 //為cid為1的評論點贊
- DELETE:刪除資源 DELETE /comments/cid/1 //刪除cid為1的評論
3. Response
- 採用JSON,不要使用XML
- 預設情況下JSON外層不需要巢狀大括號,API需要支援JSONP跨域訪問或者客戶端無法訪問HTTP Header才需要加上巢狀大括號
- 預設情況下不要過濾API輸出中的空格,並且要支援gzip
4. API版本控制
- 在URI中存放:GET /v1/comments;
- 客戶端在Accept Header中存放:Accept: application/vnd.github.v3+json,伺服器自定義Header返回當前版本資訊:X-GitHub-Media-Type: github.v3; format=json(GitHub在用);
- 以上兩種方法根據情況選擇,Github用的方式是REST中所要求的方式;
- 測試API和正式API要進行區分,方式通過如上兩種方式實現。
5. 速度限制
為了避免請求氾濫,給API設定速度限制很重要。為此 RFC 6585 引入了HTTP狀態碼429(too many requests)。加入速度設定之後,應該提示使用者,至於如何提示標準上沒有說明,不過流行的方法是使用HTTP的返回頭。 下面是幾個必須的返回頭(依照twitter的命名規則):
- X-Rate-Limit-Limit :當前時間段允許的併發請求數
- X-Rate-Limit-Remaining:當前時間段保留的請求數。
- X-Rate-Limit-Reset:當前時間段剩餘秒數
為什麼使用當前時間段剩餘秒數而不是時間戳?
時間戳儲存的資訊很多,但是也包含了很多不必要的資訊,使用者只需要知道還剩幾秒就可以再發請求了這樣也避免了clock skew問題。
6.快取
HTTP提供了自帶的快取框架。你需要做的是在返回的時候加入一些返回頭資訊,在接受輸入的時候加入輸入驗證。基本兩種方法:
- ETag:當生成請求的時候,在HTTP頭裡面加入ETag,其中包含請求的校驗和和雜湊值,這個值和在輸入變化的時候也應該變化。如果輸入的HTTP請求包含IF-NONE-MATCH頭以及一個ETag值,那麼API應該返回304 not modified狀態碼,而不是常規的輸出結果。
- Last-Modified:和etag一樣,只是多了一個時間戳。返回頭裡的Last-Modified:包含了 RFC 1123 時間戳,它和IF-MODIFIED-SINCE一致。HTTP規範裡面有三種date格式,伺服器應該都能處理。
7.覆蓋HTTP方法
一些HTTP客戶端只支援GET和POST請求。為了能夠加強這些客戶端的訪問能力,API需要能夠覆蓋HTTP方法。儘管這裡沒有任何強制的標準,但流行的做法是API會接收一個請求頭X-HTTP-Method-Override,它的值可以是PUT、PATCH或者DELETE三者之一。
注意,用來覆蓋HTTP方法的header只能在POST請求中被接受。GET請求永遠不能修改伺服器上的資料。
8.過濾資訊
如果記錄數量很多,伺服器不可能都將它們返回給使用者。API應該提供引數,過濾返回結果。
下面是一些常見的引數:
?limit=10:指定返回記錄的數量 ?offset=10:指定返回記錄的開始位置。 ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。 ?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。 ?animal_type_id=1:指定篩選條件
就像HTML的出錯頁面向訪問者展示了有用的錯誤訊息一樣,API也應該用之前熟悉易讀的格式來提供有用的錯誤訊息。錯誤的表現形式應該跟其他資源保持一致,只是用一些自己的欄位。
API應該一直返回合理的HTTP狀態碼。API錯誤一般情況下分成兩類:代表客戶端錯誤的400系列狀態碼和代表服務端錯誤的500系列狀態碼。API至少把所有400系列錯誤統一用易讀的JSON格式來展示。如果可能(比如,如果負載均衡和反向代理能夠建立自定義錯誤內容的話),500系列的狀態碼也這麼弄。
JSON錯誤內容應該為開發者提供一些東西 – 有用的錯誤訊息,唯一的錯誤碼(通過它可以在文件中找到更多錯誤細節),可能的話提供錯誤細節描述。用JSON格式來輸出錯誤看起來這樣:
{ "code" : 1234, "message" : "Something bad happened : (", "description" : "More details about the error here"}
對於PUT、PATCH和POST的請求進行的校驗錯誤需要巢狀多個欄位。最佳做法是用固定的錯誤碼來表示校驗失敗,然後在額外的errors欄位中提供錯誤的細節,像這樣:
{ "code" : 1024, "message" : "Validation Failed", "errors" : [ { "code" : 5432, "field" : "first_name", "message" : "First name cannot have fancy characters" }, { "code" : 5622, "field" : "password", "message" : "Password cannot be blank" } ] }
10.HTTP狀態碼
HTTP定義了很多有意義的狀態碼,你可以在你的API中使用。這些狀態碼可以幫助API消費者用來路由它們獲取到的響應內容。整理了一個你肯定會用到的狀態碼列表:
- 200 OK – 對成功的GET、PUT、PATCH或DELETE操作進行響應。也可以被用在不建立新資源的POST操作上
- 201 Created – 對建立新資源的POST操作進行響應。應該帶著指向新資源地址的Location header)
- 204 No Content – 對不會返回響應體的成功請求進行響應(比如DELETE請求)
- 304 Not Modified – HTTP快取header生效的時候用
- 400 Bad Request – 請求異常,比如請求中的body無法解析
- 401 Unauthorized – 沒有進行認證或者認證非法。當API通過瀏覽器訪問的時候,可以用來彈出一個認證對話方塊
- 403 Forbidden – 當認證成功,但是認證過的使用者沒有訪問資源的許可權
- 404 Not Found – 當一個不存在的資源被請求
- 405 Method Not Allowed – 所請求的HTTP方法不允許當前認證使用者訪問
- 410 Gone – 表示當前請求的資源不再可用。當呼叫老版本API的時候很有用
- 415 Unsupported Media Type – 如果請求中的內容型別是錯誤的
- 422 Unprocessable Entity – 用來表示校驗錯誤
- 429 Too Many Requests – 由於請求頻次達到上限而被拒絕訪問
11.認證
RESTful API應該是無狀態。這意味著對請求的認證不應該基於cookie或者session。相反,每個請求應該帶有一些認證憑證。
如果一直使用SSL,認證憑證可以簡單的使用隨機生成的access token,把其做為HTTP Basic Auth中user name欄位的值傳給API。這麼做的好處是可以通過瀏覽器訪問 – 如果瀏覽器從伺服器收到401 Unauthorized狀態碼,它將會彈出一個對話方塊讓人輸出認證憑證。
當然,這種基於token來進行基本認證的方法只能當用戶從API管理後臺拷貝了一個token到自己的程式碼中才行。如果搞不到token,只能使用OAuth 2來把安全token傳遞給第三方。OAuth 2使用Bearer token,並且也是基於SSL來保證傳輸安全。
支援JSONP的API可能需要第三種方法來實現認證,因為JSONP的請求沒法傳送HTTP Basic Auth憑證或者Bearer token。這種情況下,可以使用一個額外的查詢引數access_token。注意:使用查詢引數來傳遞token存在一個固有的安全隱患,因為大多數web伺服器會在伺服器日誌中儲存查詢引數。
不管怎麼樣,以上三種方法是用來在API之間傳輸token的方法。實際傳輸的token可以是一樣的。
12.使用SSL
一定要使用SSL。沒有例外。如今,你的web API可以從任何有網際網路的地方(像圖書館,咖啡館,機場等等)被訪問到。這些地方並不都是安全的。很多地方根本沒有對網路連線進行加密,如果認證憑證被劫持的話,這樣訪問者很容易被竊聽或者被冒充。
一直使用SSL的另一個優勢是,加密的連線簡化了使用者認證的工作 – 你可以使用簡單的access token,而不需要對每個API請求進行簽名。
需要注意的一件事是以非SSL的形式訪問API的URL。不要把請求跳轉到它們的SSL版本上。直接丟擲一個嚴重錯誤!
13.Hypermedia API
RESTful API最好做到Hypermedia,即返回結果中提供連結,連向其他API方法,使得使用者不查文件,也知道下一步應該做什麼。 比如,當用戶向http://api.example.com的根目錄發出請求,會得到這樣一個文件。
{"link": { "rel": "collection https://www.example.com/comments", "href": "https://api.example.com/comments", "title": "List of comments", "type": "application/vnd.yourformat+json"}}
上面程式碼表示,文件中有一個link屬性,使用者讀取這個屬性就知道下一步該呼叫什麼API了。rel表示這個API與當前網址的關係(collection關係,並給出該collection的網址),href表示API的路徑,title表示API的標題,type表示返回型別。 Hypermedia API的設計被稱為HATEOAS。
在進行分頁查詢時可以返回下一頁的URI,如果沒有說明伺服器已經取到最後一條資料了,客戶端可以減少不必要的請求以及URI的構造,建議在分頁的情況下使用。
原文釋出於微信公眾號 - java一日一條(mjx_java)
原文發表時間:2017-03-14
本文參與騰訊雲自媒體分享計劃,歡迎正在閱讀的你也加入,一起分享。
發表於 2018-09-14
https://cloud.tencent.com/developer/article/1338736