亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

RESTful設計方法和規范

在初步了解了 RESTful 之后,我們接到一項任務,需要為一所學校開發一套師生管理系統,客戶要求所開發的系統能在 PC 桌面通過瀏覽器使用,而且日后還想開發 IOS 和 Android 應用。了解需求之后,我們毫不猶豫選擇了前后端分離的開發模式,并且決定遵從時下最為流行的 RESTful 規范。接下來,我們就以后端開發人員的角色,一起來了解整個開發過程。

1. 域名(Domain)

根據 RESTful 規范,應該盡量使用專用的域名用于部署 API,于是我們和校方溝通,使用下方域名作為 API 訪問地址:

https://api.demo.com

但是經過溝通,發現上述域名已被占用,校方否決了我們的提議,考慮到 API 相對簡單,于是我們使用下面地址部署 API:

https://www.demo.com/api

上述地址中,https 代表協議名稱,常見的還有 http,二者區別在于前者在傳輸過程中是將信息加密后傳輸的,而后者是明文傳輸;www.demo.com 為域名,可以理解成某個機房里一臺電腦的地址,通過這個地址,就能訪問這臺電腦提供的資源;api 代表一個資源路徑,可以想象成這臺電腦中一個文件夾的路徑。

2. 版本(Versioning)

師生管理系統不是一成不變的,日后還要更新維護。為了區分不同版本,API 的 URL 中應當包含 API 版本信息:

http://www.demo.com/api/1.0/foo

http://www.demo.com/api/1.1/foo

http://www.demo.com/api/2.0/foo

除了上述方法外,API 版本信息還可放在 HTTP 請求頭中。Github 采用的就是這種做法。

因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該采用同一個 URL。版本號可以在 HTTP 請求頭信息的 Accept 字段中進行區分(參見Versioning REST Services):

Accept: vnd.example-com.foo+json; version=1.0

Accept: vnd.example-com.foo+json; version=1.1

Accept: vnd.example-com.foo+json; version=2.0

實際工作中,通常采用第一種方法,因為這樣的方式更加直觀,方便使用。

3. 路徑(Endpoint)

路徑即"終點"(endpoint),是訪問 API 的具體網址,通過訪問每個網址,可以獲取到相應的資源(resource)。在師生管理系統中,所謂資源,就是我們想獲取的信息,比如獲取 3 年 2 班所有學生姓名,獲取小明的年齡、成績等。

路徑須滿足以下規范:

1. 資源路徑中應當使用名詞,杜絕動詞。資源路徑中的名詞,應當與數據庫的表名相對應。

以下路徑中包含動詞,是不符合規范的例子,在實際工作中,應當避免。

/getStudents	:獲取學生信息
/listTeachers	:獲取老師信息
/retreiveStudentByID?Id=2020	:獲取ID為2020的學生信息

對于資源的操作,應該通過 HTTP 中的不同方法來區分處理資源的動作,資源路徑中應當只包含名詞。

GET /students :將返回所有學生信息
POST /students :將新增的學生信息存入數據庫
GET /students/4 :獲取編號為4號的學生信息
PATCH(或)PUT /students/4 :更新編號為4的學生信息

2. API 中的名詞應該使用復數。無論是子資源或者是所有資源。

例如:

獲取單個學生信息:http://www.demo.com/students/1    :獲取編號為1的學生信息
獲取所有學生信息: http://www.demo.com/students    :獲取所有學生信息

4. HTTP動詞

對于資源的具體操作類型,由 HTTP 動詞表示。

常用的 HTTP 動詞有下面 4 個(括號里是對應的 SQL 命令)。

  • GET(SELECT):從服務器取出資源(一項或多項)
  • POST(CREATE):在服務器新建一個資源
  • PUT(UPDATE):在服務器更新資源(客戶端提供改變后的完整資源)
  • DELETE(DELETE):從服務器刪除資源

還有 3 個不常用的 HTTP 動詞。

  • PATCH(UPDATE):在服務器更新(更新)資源(客戶端提供改變的屬性)
  • HEAD:獲取資源的元數
  • OPTIONS:獲取信息,關于資源的哪些屬性是客戶端可以改變的

下面是一些例子。

GET /classes:列出所有班級
POST /classes:新建一個班級(上傳文件)
GET /classes/ID:獲取某個指定班級的信息
PUT /classes/ID:更新某個指定班級的信息(提供該班級的全部信息)
PATCH /classes/ID:更新某個指定班級的信息(提供該班級的部分信息)
DELETE /classes/ID:刪除某個班級
GET /classes/ID/students:列出某個指定班級的所有學生
DELETE /classes/ID/students/ID:刪除某個指定班級的指定學生

5. 過濾信息(Filtering)

如果記錄數量很多,服務器不可能都將它們返回給用戶。API 應該提供參數,過濾返回結果。比如,我們想獲取全校師生的個人信息,如果將這些信息一股腦地全部展示在網頁上,是不明智也是不現實的。如果數據量太大,在實際開發中我們會采用分頁展示的形式。另外,如果想在一次考試后,按照成績高低展示學生信息,那么可以通過過濾信息來實現。

所謂過濾,就是在 URL 中添加一下限制參數。下面是一些常見的參數。

?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置。
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
?sortby=score&order=asc:指定返回結果按照學生的成績(score)正序(asc)排列順序。

參數的設計允許存在冗余,即允許 API 路徑和 URL 參數允許有重復。比如,想要查詢某個班級所有學生信息,我們可以設計 GET /classes/ID/studentsGET /students?class_id=ID 兩種地址,任何一種都可得到相同的結果。

6. 狀態碼(Status Codes)

服務器向用戶返回的狀態碼和提示信息,常見的有以下一些(方括號中是該狀態碼對應的 HTTP 動詞)。不同的狀態碼代表著不同的含義,比如以 2 開頭的狀態碼通常代表服務器成功響應,3 開頭的狀態碼代表發生了重定性(即跳轉到了別的鏈接),4 開頭的狀態碼通常表示客戶端這邊提供的信息有誤,而 5 開頭的狀態碼則表示服務器內部出現的錯誤。通過返回的狀態碼,用戶即可判斷請求成功與否,不成功問題在何處。

一些常用的狀態碼列舉如下:

  • 200 OK - [GET]:服務器成功返回用戶請求的數據
  • 201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
  • 202 Accepted - [*]:表示一個請求已經進入后臺排隊(異步任務)
  • 204 NO CONTENT - [DELETE]:用戶刪除數據成功
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操作
  • 401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)
  • 403 Forbidden - [*] 表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的
  • 404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操作,該操作是冪等的
  • 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)
  • 410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的
  • 422 Unprocesable entity - [POST/PUT/PATCH]: 當創建一個對象時,發生一個驗證錯誤
  • 500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功

狀態碼的完全列表參見這里這里。

7. 錯誤信息

如果狀態碼是 4xx,服務器就應該向用戶返回出錯信息。一般來說,返回的信息是鍵值對形式的數據,將 error 作為鍵名,出錯信息作為鍵值即可。比如,在一個提供查詢學生信息的 API 中,要求客戶端提供正確的 API key(可以理解為輸入了正確的用戶名和密碼)才能訪問,如果提供的 API key 不正確,此時服務器應拒絕訪問,并返回錯誤信息。這樣,客戶端就知道了為何沒能查到信息,修改成正確的 API key 即可。

{
    error: "Invalid API key"
}

8. 返回結果

針對不同操作,服務器向用戶返回的結果應該符合以下規范。

  • GET /collection:返回資源對象的列表(數組)
  • GET /collection/resource:返回單個資源對象
  • POST /collection:返回新生成的資源對象
  • PUT /collection/resource:返回完整的資源對象
  • PATCH /collection/resource:返回完整的資源對象
  • DELETE /collection/resource:返回一個空文檔

9. 超媒體鏈接

RESTful API 最好做到 Hypermedia(即返回結果中提供鏈接,連向其他 API 方法),使得用戶不查文檔,也知道下一步應該做什么。

比如,Github 的 API 就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表。

{
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}

從上面可以看到,如果想獲取當前用戶的信息,應該去訪問 api.github.com/user,然后就得到了下面結果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代碼表示,服務器給出了提示信息,以及文檔的網址。

10. 數據格式

服務器返回的數據格式,應該盡量使用 JSON,避免使用 XML。什么是 JSON 呢?什么又是 XML 呢?兩種數據格式的簡單舉例如下:

# JSON
{"name":"XiaoMing",
"age":"12",
"gender":"male"}
# XML
<?xml version="1.0" encoding="UTF-8" ?>
	<name>XiaoMing</name>
	<age>12</age>
	<gender>male</gender>
	

通過上面的對比可以看出,JSON 數據形式要遠比 XML 的數據形式來得簡單和易懂,所以現在的 Web 開發中 JSON 數據格式已經開始全面取代 XML 應用在實際開發中。

11. 小結

本節主要從域名、版本、路徑、HTTP動詞、過濾信息、狀態碼、錯誤信息、返回結果、超媒體鏈接、數據格式 10 個方面介紹了 RESTful 設計方法和設計規范。為了讓更多的人方便使用所設計的 API 接口,以上規范一定要遵守哦!