總結常見的違背Rest原則的接口設計作法

此文已由做者鄭華斌受權網易雲社區發佈。html

REST這詞咱們經常掛在嘴邊,好比「開發一個rest接口」,又好比Spring項目的代碼:web

@RestControllerpublic class CommonController { @RequestMapping("/") public String index() { return "Welcome to Yanxuan DMS!";數據庫

}

CommonController使用了@RestController註解,顧名思義,告訴讀者這是一個Rest接口的實現。然而以@RestController註解的接口卻不必定符合Rest原則。結合最近的項目,總結下常見的違背Rest設計的一些作法。json

1、一概使用POST或者GET方法
典型的錯誤作法:不管什麼請求,一概用POST,或者‘增刪改’用POST,‘查’用GET。安全

其實REST有個原則叫統一接口(uniform interface),統一接口原則建議了各http方法的使用場合,服務器

GET:獲取資源,返回消息頭和消息表示,即header和body。app

HEAD:獲取資源元數據,返回消息頭ide

DELETE:刪除資源post

POST:REST設計中,POST一般用來爲一個已有資源建立一個從屬資源(subordinate resource),如AWS S3的POST Object(或者稱web post)接口。url

PUT:建立或修改一個資源

PUT和POST的區別比較微妙,這裏拿AWS S3(或者參考網易對象存儲NOS)的接口設計來舉例。其中AWS S3的詳細API文檔參見:http://docs.aws.amazon.com/Am...。 S3有兩種資源,桶(bucket)和對象(object),對象從屬於某個桶。

建立一個桶的接口爲:

PUT /BucketName HTTP/1.1
Host: s3.amazonaws.com
建立/修改一個對象的PUT Object接口爲:

PUT /BucketName/ObjectName HTTP/1.1
Host: s3.amazonaws.com[對象數據]
AWS S3同時提供了POST Object接口,一樣能夠建立/修改一個對象,以下

POST /BucketName HTTP/1.1Host: s3.amazonaws.comContent-Type: multipart/form-data; boundary=9431149156168[包含對象數據的body]
獲取對象的GET Object接口爲:

GET /BucketName/ObjectName HTTP/1.1
Host: s3.amazonaws.com
一樣的建立/修改一個對象,一個用PUT方法,另外一個用POST方法,爲何?關鍵在於URL,PUT請求的目標URL(這裏爲/BucketName/ObjectName),就是未來用於獲取該對象的URL,即PUT Object和GET Object的URL是一致的。可是POST Object的URL與GET ObjectURL不同,POST 請求只知道父資源的URL(即/BucketName),表示在該父資源下建立新資源,至於新資源的確切URL,是由服務器決定的,通常來講是POST請求的響應應該包含一個Location消息頭,其包含新建從屬資源的URL。

安全性safe和冪等性idempotent

REST設計還應該遵循安全性和冪等性約束,以下:

GET和HEAD應當是安全的:GET和HEAD請求不該該致使服務器狀態發生改變

GET、HEAD、PUT和DELETE應當是冪等的:向一個URL發送屢次PUT和DELETE請求,跟只作過一次請求同樣。好比PUT不能是append語義,不然不冪等。GET和HEAD也是冪等。

統一接口原則的好處:

給一個資源URI,不用看文檔就知道能夠有GET、DELETE等操做及其意義,世界通用。

安全性和冪等性增長了http的可靠性:若是請求沒成功(但也許已成功了),只需從新發一次便可,不用擔憂反作用。

2、HTTP Code一概返回200
典型的錯誤作法:不管成功失敗,HTTP Code一概返回200,具體錯誤信息交由json body裏的內容來判斷,舉例以下,

某甲服務xxx接口的響應以下

HTTP/1.1 200 OK{ "status":1, //1: 成功 0: 參數異常 -1: 失敗

"message":"" //返回的消息
成功時返回的數據

}
某乙服務xxx接口的響應以下

HTTP/1.1 200 OK{ "code":200, //1: 成功 0: 參數異常 -1: 失敗

"msg":"" //code非200時返回的錯誤信息
"data":{成功時返回的數據內容}

}
其實RESTful的設計的一個標誌特徵是充分並正確利用HTTP響應碼,典型的如:

200 -- OK,成功

301 -- Moved Permanently,重定向

400 -- Bad Request,錯誤的請求,好比缺乏參數或者參數值不對

403 -- Forbidden,無權限訪問

404 -- Not Found,url不存在

500 -- Internal Server Error,系統錯誤,如數據庫訪問失敗或者bug致使的錯誤

設計REST接口應該遵循上面的響應碼,語義明確並通用。若是像上面例子那樣,任何狀況都一概返回200,而具體成功與否須要到http響應消息體裏去解析,並且不一樣的服務或開發者自定義消息體的格式,那麼服務調用方就須要針對不一樣的服務寫不一樣的判斷邏輯,增長系統交互複雜性。

有些通用的客戶端,會針對301自動處理重定向,針對500以上的響應自動重試,而一概返回200的設計是無法使用這些特性的,只能調用方一一自個處理。

3、 面向操做而不是面向資源的url設計
典型的錯誤作法:設計的URI是面向操做而不是面向資源的,舉例以下,

某系統 設計的渠道相關的URI是這樣的:

新增渠道

POST /xhr/thirdparty/admin/channel/add.json?{渠道信息參數}
編輯渠道

POST /xhr/thirdparty/admin/channel/update.json?{渠道信息參數}
刪除渠道

POST /xhr/thirdparty/admin/channel/delete.json?channelId=id
這裏的接口設計有三個特色:

http方法都是POST;

URI裏攜帶操做信息,如URI裏出現「add」,「update」,「delete」等字眼;

同一個資源因爲操做不同而URI不同。

其實REST式的設計中,URI便是資源的名稱,也是資源的地址,由於不一樣的操做而資源地址不同是不合適的。資源的操做(方法信息)應該由統一接口來表示,即http 方法PUT、POST、GET、DELETE等,而不該該放到URI中。

對照統一接口和麪向資源這兩個特徵來設計,上面的接口RESTful化能夠是這樣的:

新增渠道

POST /xhr/thirdparty/admin/channel

[渠道具體信息]
修改渠道

PUT /xhr/thirdparty/admin/channel?channelId=id 或者PUT /xhr/thirdparty/admin/channel/${id}

[渠道具體信息]
刪除渠道

DELETE /xhr/thirdparty/admin/channel?channelId=id或者DELETE /xhr/thirdparty/admin/channel/${id}
渠道的地址爲/xhr/thirdparty/admin/channel?channelId=id或者/xhr/thirdparty/admin/channel/${id},重在url惟一。

參考文獻
《RESTful Web Services》

文章來源: 網易雲社區

相關文章
相關標籤/搜索