@@ -55,46 +55,46 @@ REST 基本架构的四个方法:
5555
5656REST 定义了资源的通用访问格式,接下来一个消费者为实例,介绍 RESTful API 定义:
5757
58- 1 . 获取所有 user
58+ 1 . 获取所有 users
5959
6060```
61- GET /api/user
61+ GET /api/users
6262```
6363
64- 2 . 获取指定 id 的 user
64+ 2 . 获取指定 id 的 users
6565
6666```
67- GET /api/user /100
67+ GET /api/users /100
6868```
6969
70- 3 . 新建一条 user 记录
70+ 3 . 新建一条 users 记录
7171
7272```
73- POST /api/user
73+ POST /api/users
7474```
7575
76- 4 . 更新一条 user 记录
76+ 4 . 更新一条 users 记录
7777
7878```
79- PUT /api/user /100
79+ PUT /api/users /100
8080```
8181
82- 5 . 删除一条 user 记录
82+ 5 . 删除一条 users 记录
8383
8484```
85- DELETE /api/user /100
85+ DELETE /api/users /100
8686```
8787
88- 6 . 获取一个 user 的所有消费账单
88+ 6 . 获取一个 users 的所有消费账单
8989
9090```
91- GET /api/user /100/bill
91+ GET /api/users /100/bill
9292```
9393
94947 . 获取一个 user 指定时间的消费账单
9595
9696```
97- GET /api/user /100/bill?from=201910&to=201911
97+ GET /api/users /100/bill?from=201910&to=201911
9898```
9999
100100以上其中 RESTful 风格 API 几乎包含常见业务情况。
@@ -132,7 +132,7 @@ GET /api/user/100/bill?from=201910&to=201911
132132
133133### 2. 获取用户列表
134134
135- 这一步我们会创建 RESTful API 中的 ** user ** ,使用 GET 来** 读取用户的信息列表** :
135+ 这一步我们会创建 RESTful API 中的 ** /users ** ,使用 GET 来** 读取用户的信息列表** :
136136
137137``` js
138138// index.js
@@ -141,7 +141,7 @@ const app = express();
141141const fs = require (" fs" );
142142
143143// 定义 读取用户的信息列表 的接口
144- app .get (' /user ' , (req , res ) => {
144+ app .get (' /users ' , (req , res ) => {
145145 fs .readFile ( __dirname + " /" + " users.json" , ' utf8' , (err , data ) => {
146146 console .log ( data );
147147 res .end ( data );
@@ -156,7 +156,7 @@ const server = app.listen(8081, function () {
156156
157157### 3. 添加用户
158158
159- 这一步我们会创建 RESTful API 中的 ** user ** ,使用 POST 来** 添加用户记录** :
159+ 这一步我们会创建 RESTful API 中的 ** /users ** ,使用 POST 来** 添加用户记录** :
160160
161161``` js
162162// index.js
@@ -173,7 +173,7 @@ const user = {
173173}
174174
175175// 定义 添加用户记录 的接口
176- app .post (' /user ' , (req , res ) => {
176+ app .post (' /users ' , (req , res ) => {
177177 // 读取已存在的数据
178178 fs .readFile ( __dirname + " /" + " users.json" , ' utf8' , (err , data ) => {
179179 data = JSON .parse ( data );
@@ -186,14 +186,14 @@ app.post('/user', (req, res) => {
186186
187187### 4. 获取用户详情
188188
189- 这一步我们在 RESTful API 中的 URI 后面加上 ** : id ** ,使用 GET 来** 获取指定用户详情** :
189+ 这一步我们在 RESTful API 中的 URI 后面加上 ** /users/ : id ** ,使用 GET 来** 获取指定用户详情** :
190190
191191``` js
192192// index.js
193193// 省略之前文件 只展示需要实现的接口
194194
195195// 定义 获取指定用户详情 的接口
196- app .get (' /:id' , (req , res ) => {
196+ app .get (' /users/ :id' , (req , res ) => {
197197 // 首先我们读取已存在的用户
198198 fs .readFile ( __dirname + " /" + " users.json" , ' utf8' , (err , data ) => {
199199 data = JSON .parse ( data );
@@ -206,7 +206,7 @@ app.get('/:id', (req, res) => {
206206
207207### 5. 删除指定用户
208208
209- 这一步我们会创建 RESTful API 中的 ** user ** ,使用 DELETE 来** 删除指定用户** :
209+ 这一步我们会创建 RESTful API 中的 ** /users ** ,使用 DELETE 来** 删除指定用户** :
210210
211211``` js
212212// index.js
@@ -215,7 +215,7 @@ app.get('/:id', (req, res) => {
215215// mock 一条要删除的用户id
216216const id = 2 ;
217217
218- app .delete (' /user ' , (req , res ) => {
218+ app .delete (' /users ' , (req , res ) => {
219219 fs .readFile ( __dirname + " /" + " users.json" , ' utf8' , (err , data ) => {
220220 data = JSON .parse ( data );
221221 delete data[" user" + id];
@@ -225,12 +225,114 @@ app.delete('/user', (req, res) => {
225225})
226226```
227227
228+ ## 四、REST 最佳实践
229+
230+ ### 1. URL 设计
231+
232+ #### 1.1 "动词 + 宾语"的操作指令结构
233+
234+ 客户端发出的数据操作指令都是"** 动词 + 宾语** "的结构。
235+
236+ 如上面提到的,` GET /user ` 这个命令,` GET ` 是动词,` /user ` 是宾语。根据 HTTP 规范,动词一律大写。
237+
238+ 动词通常有以下五种 HTTP 方法:
239+
240+ GET:读取(Read)
241+ POST:新建(Create)
242+ PUT:更新(Update)
243+ PATCH:更新(Update),通常是部分更新
244+ DELETE:删除(Delete)
245+
246+ #### 1.2 宾语必须是名词
247+ 宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。
248+
249+ 比如,` /users ` 是正确的,因为 URL 是名词,而下面就都是错误的了:
250+ ```
251+ /getUsers
252+ /createUsers
253+ /deleteUsers
254+ ```
255+
256+ #### 1.3 建议复数 URL
257+
258+ 因为 URL 是名词,没有单复数的限制,但是还是建议如果是一个集合,就使用复数形式。如 ` GET /users ` 来读取所有用户列表。
259+
260+ #### 1.4 避免多级 URL
261+
262+ 避免在多层级资源时,使用多级 URL。常见案例如** 获取某位用户的购买过的某一类商品** :
263+
264+ ```
265+ GET /users/100/product/120
266+ ```
267+
268+ 这种 URL 语意不明,也不利拓展,建议只有第一级,其他级别用查询字符串来表达:
269+
270+ ```
271+ GET /users/100?product=120
272+ ```
273+
274+ ### 2. 准确的状态码表示
275+
276+ HTTP 五大类状态码有100多种,每一种状态码都有标准的(或者约定的)解释,客户端只需查看状态码,就可以判断出发生了什么情况,所以服务器应该返回尽可能精确的状态码。
277+
278+ 这边列举几个经常使用的状态码介绍:
279+
280+ * ** 303 See Other** :表示参考另一个 URL。
281+
282+ * ** 400 Bad Request** :服务器不理解客户端的请求,未做任何处理。
283+
284+ * ** 401 Unauthorized** :用户未提供身份验证凭据,或者没有通过身份验证。
285+
286+ * ** 403 Forbidden** :用户通过了身份验证,但是不具有访问资源所需的权限。
287+
288+ * ** 404 Not Found** :所请求的资源不存在,或不可用。
289+
290+ * ** 405 Method Not Allowed** :用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内。
291+
292+ * ** 410 Gone** :所请求的资源已从这个地址转移,不再可用。
293+
294+ * ** 415 Unsupported Media Type** :客户端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。
295+
296+ * ** 422 Unprocessable Entity** :客户端上传的附件无法处理,导致请求失败。
297+
298+ * ** 429 Too Many Requests** :客户端的请求次数超过限额。
299+
300+ * ** 500 Internal Server Error** :客户端请求有效,服务器处理时发生了意外。
301+
302+ * ** 503 Service Unavailable** :服务器无法处理请求,一般用于网站维护状态。
303+
304+ ### 3. 服务端响应
305+
306+ #### 3.1 应该返回 JSON 对象
228307
308+ API 返回的数据格式应该是 JSON 一个对象。
309+
310+ #### 3.2 发生错误时,不要返回 200 状态码
311+
312+ 在发生错误时,如果还返回 200 状态码,前端需要解析返回数据才知道错误信息,这样实际上取消了状态码,是不恰当的。
313+
314+ 正确的做法应该是在错误时,返回对应错误状态码,并将错误信息返回:
315+
316+ ```
317+ HTTP/1.1 400 Bad Request
318+ Content-Type: application/json
319+
320+ {
321+ "error": "Invalid payoad.",
322+ "detail": {
323+ "surname": "This field is required."
324+ }
325+ }
326+ ```
327+
328+
329+
229330## 参考资料
230331
2313321 . [ 《维基百科 - 表现层状态转换》] ( https://zh.wikipedia.org/wiki/%E8%A1%A8%E7%8E%B0%E5%B1%82%E7%8A%B6%E6%80%81%E8%BD%AC%E6%8D%A2 )
2323332 . [ 《RESTful风格的springMVC》] ( https://blog.csdn.net/wy5612087/article/details/52149249 )
2333343 . [ 《Node.js RESTful API》] ( https://www.runoob.com/nodejs/nodejs-restful-api.html )
335+ 4 . [ 《RESTful API 最佳实践》] ( www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html )
234336
235337## 关于我
236338
0 commit comments