一、概念介紹1. REST 概念REST:(Representational State Transfer)即表現(xiàn)層狀態(tài)轉(zhuǎn)換,定義了資源的通用訪問格式,是一種網(wǎng)絡應用程序的設計風格和開發(fā)方式。 在概念中,需要理解以下幾個名稱: 資源(Resource)
即服務器上獲取到的東西任何資源,一條用戶記錄,一個用戶的密碼,一張圖片等等都是。 資源的表述(Representation)
即資源格式,是 HTML、XML、JSON、純文本、圖片等等,可以用各種各樣的格式來表述你獲取到的資源。 狀態(tài)轉(zhuǎn)移(State Transfer)
即URL定位資源,用 HTTP 動詞(GET,POST,DELETE,DETC)描述操作。操作是動詞,資源是名詞。 統(tǒng)一接口(Uniform Interface)
即通過統(tǒng)一的接口對資源進行操作。 2. REST 特點REST 通?;谑褂?HTTP , URI ,和 XML 以及 HTML 這些現(xiàn)有的廣泛流行的協(xié)議和標準,每一種 URI 代表一種資源。 REST 通常使用 JSON 數(shù)據(jù)格式。 REST 基本架構(gòu)的四個方法: GET - 用于獲取數(shù)據(jù) PUT - 用于更新或添加數(shù)據(jù) DELETE - 用于刪除數(shù)據(jù) POST - 用于添加數(shù)據(jù)
下面會通過一個場景介紹。 3. REST 優(yōu)點二、實例介紹REST 定義了資源的通用訪問格式,接下來一個消費者為實例,介紹 RESTful API 定義: 獲取所有 users
GET /api/users
獲取指定 id 的 users
GET /api/users/100
新建一條 users 記錄
POST /api/users
更新一條 users 記錄
PUT /api/users/100
刪除一條 users 記錄
DELETE /api/users/100
獲取一個 users 的所有消費賬單
GET /api/users/100/bill
獲取一個 user 指定時間的消費賬單
GET /api/users/100/bill?from=201910&to=201911
以上其中 RESTful 風格 API 幾乎包含常見業(yè)務情況。 三、Nodejs 實現(xiàn) RESTful API1. 初始化 mock 數(shù)據(jù)本案例使用 mock 數(shù)據(jù)來演示,如下: {
"user1" : { "name" : "leo", "password" : "123456", "profession" : "teacher", "id": 1
},
"user2" : { "name" : "pingan8787", "password" : "654321", "profession" : "librarian", "id": 2
},
"user3" : { "name" : "robin", "password" : "888888", "profession" : "clerk", "id": 3
}}
我們將實現(xiàn)以下 RESTful API : 2. 獲取用戶列表這一步我們會創(chuàng)建 RESTful API 中的 /users,使用 GET 來讀取用戶的信息列表: // index.jsconst express = require('express');const app = express();const fs = require("fs");// 定義 讀取用戶的信息列表 的接口app.get('/users', (req, res) => {
fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => { console.log( data ); res.end( data );
});})const server = app.listen(8081, function () {const {address, port} = server.address();console.log("server run in: http://%s:%s", address, port);})
3. 添加用戶這一步我們會創(chuàng)建 RESTful API 中的 /users,使用 POST 來添加用戶記錄: // index.js// 省略之前文件 只展示需要實現(xiàn)的接口// mock 一條要新增的數(shù)據(jù)const user = {
"user4" : { "name" : "pingan", "password" : "password4", "profession" : "teacher", "id": 4
}}// 定義 添加用戶記錄 的接口app.post('/users', (req, res) => {
// 讀取已存在的數(shù)據(jù)
fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => { data = JSON.parse( data ); data["user4"] = user["user4"]; console.log( data ); res.end( JSON.stringify(data));
});})
4. 獲取用戶詳情這一步我們在 RESTful API 中的 URI 后面加上 /users/:id,使用 GET 來獲取指定用戶詳情: // index.js// 省略之前文件 只展示需要實現(xiàn)的接口// 定義 獲取指定用戶詳情 的接口app.get('/users/:id', (req, res) => {
// 首先我們讀取已存在的用戶
fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => { data = JSON.parse( data ); const user = data["user" + req.params.id]
console.log( user ); res.end( JSON.stringify(user));
});})
5. 刪除指定用戶這一步我們會創(chuàng)建 RESTful API 中的 /users,使用 DELETE 來刪除指定用戶: // index.js// 省略之前文件 只展示需要實現(xiàn)的接口// mock 一條要刪除的用戶idconst id = 2;app.delete('/users', (req, res) => {
fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => { data = JSON.parse( data ); delete data["user" + id]; console.log( data ); res.end( JSON.stringify(data));
});})
四、REST 最佳實踐1. URL 設計1.1 "動詞 + 賓語"的操作指令結(jié)構(gòu)客戶端發(fā)出的數(shù)據(jù)操作指令都是"動詞 + 賓語"的結(jié)構(gòu)。 如上面提到的,GET /user 這個命令,GET 是動詞,/user 是賓語。根據(jù) HTTP 規(guī)范,動詞一律大寫。 動詞通常有以下五種 HTTP 方法: GET:讀?。≧ead) POST:新建(Create) PUT:更新(Update) PATCH:更新(Update),通常是部分更新 DELETE:刪除(Delete) 1.2 賓語必須是名詞賓語就是 API 的 URL,是 HTTP 動詞作用的對象。它應該是名詞,不能是動詞。 比如,/users 是正確的,因為 URL 是名詞,而下面就都是錯誤的了: /getUsers
/createUsers
/deleteUsers
1.3 建議復數(shù) URL因為 URL 是名詞,沒有單復數(shù)的限制,但是還是建議如果是一個集合,就使用復數(shù)形式。如 GET /users 來讀取所有用戶列表。 1.4 避免多級 URL避免在多層級資源時,使用多級 URL。常見案例如獲取某位用戶的購買過的某一類商品: GET /users/100/product/120
這種 URL 語意不明,也不利拓展,建議只有第一級,其他級別用查詢字符串來表達: GET /users/100?product=120
2. 準確的狀態(tài)碼表示HTTP 五大類狀態(tài)碼有100多種,每一種狀態(tài)碼都有標準的(或者約定的)解釋,客戶端只需查看狀態(tài)碼,就可以判斷出發(fā)生了什么情況,所以服務器應該返回盡可能精確的狀態(tài)碼。 這邊列舉幾個經(jīng)常使用的狀態(tài)碼介紹: 303 See Other:表示參考另一個 URL。 400 Bad Request:服務器不理解客戶端的請求,未做任何處理。 401 Unauthorized:用戶未提供身份驗證憑據(jù),或者沒有通過身份驗證。 403 Forbidden:用戶通過了身份驗證,但是不具有訪問資源所需的權(quán)限。 404 Not Found:所請求的資源不存在,或不可用。 405 Method Not Allowed:用戶已經(jīng)通過身份驗證,但是所用的 HTTP 方法不在他的權(quán)限之內(nèi)。 410 Gone:所請求的資源已從這個地址轉(zhuǎn)移,不再可用。 415 Unsupported Media Type:客戶端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客戶端要求返回 XML 格式。 422 Unprocessable Entity:客戶端上傳的附件無法處理,導致請求失敗。 429 Too Many Requests:客戶端的請求次數(shù)超過限額。 500 Internal Server Error:客戶端請求有效,服務器處理時發(fā)生了意外。 503 Service Unavailable:服務器無法處理請求,一般用于網(wǎng)站維護狀態(tài)。
3. 服務端響應3.1 應該返回 JSON 對象API 返回的數(shù)據(jù)格式應該是 JSON 一個對象。 3.2 發(fā)生錯誤時,不要返回 200 狀態(tài)碼在發(fā)生錯誤時,如果還返回 200 狀態(tài)碼,前端需要解析返回數(shù)據(jù)才知道錯誤信息,這樣實際上取消了狀態(tài)碼,是不恰當?shù)摹?/p> 正確的做法應該是在錯誤時,返回對應錯誤狀態(tài)碼,并將錯誤信息返回: HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}
}
參考資料《維基百科 - 表現(xiàn)層狀態(tài)轉(zhuǎn)換》 《RESTful風格的springMVC》 《Node.js RESTful API》 《RESTful API 最佳實踐》
關(guān)于我本文首發(fā)在 pingan8787個人博客,如需轉(zhuǎn)載請聯(lián)系本人。
Author | 王平安 |
---|
E-mail | pingan8787@qq.com | 博 客 | www.pingan8787.com | 微 信 | pingan8787 | 每日文章推薦 | https://github.com/pingan8787/Leo_Reading/issues | ES小冊 | js.pingan8787.com |
|