一、說明
REST表示 Representational State Transfer(表示性狀態轉換). 它是可以用來設計web services的框架,可以被不同的客戶端調用。 REST是一種架構風格,其核心是面向資源,REST專門針對網絡應用設計和開發方式,以降低開發的復雜性,提高系統的可伸縮性。
二、REST提出設計概念和準則
1.網絡上的所有事物都可以被抽象為資源(resource) 2.每一個資源都有唯一的資源標識(resource identifier),對資源的操作不會改變這些標識 3.所有的操作都是無狀態的 使用簡單的HTTP協議來實現調用,而不是CORBA, RPC 或者 SOAP等負責的機制。
三、RESTful API 設計指南
1、概述
網絡應用程序,分為前端和后端兩個部分。當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其他專用設備......)。 因此,必須有一種統一的機制,方便不同的前端設備與后端進行通信。 1.協議 API與用戶的通信協議,總是使用HTTPs協議。 2.域名 應該盡量將API部署在專用域名之下。 https://api.example.com 如果確定API很簡單,不會有進一步擴展,可以考慮放在主域名下。 https://example.org/api/ 3.版本(Versioning) 應該將API的版本號放入URL。 https://api.example.com/v1/ 另一種做法是,將版本號放在HTTP頭信息中,但不如放入URL方便和直觀。Github采用這種做法。 4.路徑(Endpoint) 路徑又稱"終點"(endpoint),表示API的具體網址。 在RESTful架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞, 而且所用的名詞往往與數據庫的表格名對應。 一般來說,數據庫中的表都是同種記錄的"集合"(collection),所以API中的名詞也應該使用復數。 5.HTTP動詞 對于資源的具體操作類型,由HTTP動詞表示。 常用的HTTP動詞 GET(SELECT):從服務器取出資源(一項或多項)。 POST(CREATE):在服務器新建一個資源。 PUT(UPDATE):在服務器更新資源(客戶端提供改變后的完整資源)。 PATCH(UPDATE):在服務器更新資源(客戶端提供改變的屬性)。 DELETE(DELETE):從服務器刪除資源。 動詞舉例 GET /zoos:列出所有動物園 POST /zoos:新建一個動物園 GET /zoos/ID:獲取某個指定動物園的信息 PUT /zoos/ID:更新某個指定動物園的信息(提供該動物園的全部信息) PATCH /zoos/ID:更新某個指定動物園的信息(提供該動物園的部分信息) DELETE /zoos/ID:刪除某個動物園 GET /zoos/ID/animals:列出某個指定動物園的所有動物 DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物 6.過濾信息(Filtering) 如果記錄數量很多,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果。 常見的參數 ?limit=10:指定返回記錄的數量 ?offset=10:指定返回記錄的開始位置。 ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。 ?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。 ?animal_type_id=1:指定篩選條件 參數的設計允許存在冗余,即允許API路徑和URL參數偶爾有重復。 比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。 7.狀態碼(Status Codes) 服務器向用戶返回的狀態碼和提示信息 常見的狀態碼 200 OK - [GET]:服務器成功返回用戶請求的數據,該操作是冪等的(Idempotent)。 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 - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功。 8.錯誤處理(Error handling) 如果狀態碼是4xx,就應該向用戶返回出錯信息。一般來說,返回的信息中將error作為鍵名,出錯信息作為鍵值即可。 eg: { error: "Invalid API key" } 9.返回結果 針對不同操作,服務器向用戶返回的結果應該符合以下規范。 GET /collection:返回資源對象的列表(數組) GET /collection/resource:返回單個資源對象 POST /collection:返回新生成的資源對象 PUT /collection/resource:返回完整的資源對象 PATCH /collection/resource:返回完整的資源對象 DELETE /collection/resource:返回一個空文檔 10.Hypermedia API RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什么。 11.其他 (1)API的身份認證應該使用OAuth 2.0框架。 (2)服務器返回的數據格式,應該盡量使用JSON,避免使用XML。
2、返回數據類型
盡管沒有限制必須返回的類型,但是一般基于Web services的Rest返回JSON或者XML作為響應。 客戶端可以指定(使用HTTP Accept header)他們想要的資源類型嗎,服務器返回需要的資源。 指明資源的Content-Type。
3、REST API
GET 方式請求 /api/user/ 返回用戶列表 GET 方式請求 /api/user/1返回id為1的用戶 POST 方式請求 /api/user/ 通過user對象的JSON 參數創建新的user對象 PUT 方式請求 /api/user/3 更新id為3的發送json格式的用戶對象 DELETE 方式請求/api/user/4刪除 ID為 4的user對象 DELETE 方式請求/api/user/刪除所有user
4、Spring4 Rest 注解
@RestController 此注解避免了每個方法都要加上@ResponseBody注解。也就是說@RestController 自己戴上了 @ResponseBody注解,看以看作是 @Controller 和 @ResponseBody的結合體。 @RestController,表明該類的每個方法返回對象而不是視圖。 它實際就是@Controller和@ResponseBody混合使用的簡寫方法。 @RequestBody 如果方法參數被 @RequestBody注解,Spring將綁定HTTP請求體到那個參數上。 如果那樣做,Spring將根據請求中的ACCEPT或者 Content-Type header(私下)使用 HTTP Message converters 來將http請求體轉化為domain對象。 @ResponseBody 如果方法加上了@ResponseBody注解,Spring返回值到響應體。如果這樣做的話,Spring將根據請求中的 Content-Type header(私下)使用 HTTP Message converters 來將domain對象轉換為響應體。 @ResponseBody的作用是將返回的對象放入響應消息體中 ResponseEntity 是一個真實數據.它代表了整個 HTTP 響應(response). 它的好處是你可以控制任何對象放到它內部。 可以指定狀態碼、頭信息和響應體。它包含你想要構建HTTP Response 的信息。 @PathVariable 此注解意味著一個方法參數應該綁定到一個url模板變量[在'{}'里的一個]中 MediaType 帶著 @RequestMapping 注解,通過特殊的控制器方法你可以額外指定,MediaType來生產或者消耗。
5、REST測試
POSTMAN測試 使用RestTemplate編寫測試用例 HTTP GET : getForObject, getForEntity HTTP PUT : put(String url, Object request, String…urlVariables) HTTP DELETE : delete HTTP POST : postForLocation(String url, Object request, String… urlVariables), postForObject(String url, Object request, ClassresponseType, String… uriVariables) HTTP HEAD : headForHeaders(String url, String… urlVariables) HTTP OPTIONS : optionsForAllow(String url, String… urlVariables) HTTP PATCH and others : exchange execute
6、others
REST的優勢 由于REST強制所有的操作都必須是stateless的,這就沒有上下文的約束,如果做分布式,集群都不需要考慮上下文和會話保持的問題。極大的提高系統的可伸縮性 Webservice選擇 SOAP偏向于面向活動,有嚴格的規范和標準,包括安全,事務等各個方面的內容, 同時SOAP強調操作方法和操作對象的分離,有WSDL文件規范和XSD文件分別對其定義。 REST強調面向資源 只要我們要操作的對象可以抽象為資源即可以使用REST架構風格。 REST ful 應用問題 是否使用REST就需要考慮資源本身的抽象和識別是否困難,如果本身就是簡單的類似增刪改查的業務操作,那么抽象資源就比較容易,而對于復雜的業務活動抽象資源并不是一個簡單的事情。比如校驗用戶等級,轉賬,事務處理等,這些往往并不容易簡單的抽象為資源。 其次如果有嚴格的規范和標準定義要求,而且前期規范標準需要指導多個業務系統集成和開發的時候,SOAP風格由于有清晰的規范標準定義是明顯有優勢的。我們可以在開始和實現之前就嚴格定義相關的接口方法和接口傳輸數據。
四、示例
package com.qianfeng.controller;
import com.qianfeng.bean.User;
import com.qianfeng.service.IUserSevice;
import com.qianfeng.service.impl.UserServiceImpl;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class UserController {
private IUserSevice userSevice = new UserServiceImpl();
@GetMapping("/users")
public List<User> getAllUsers(){
return userSevice.getAllUsers();
}
@GetMapping("/users/{uid}")
public User getUserById(@PathVariable int uid){
return userSevice.getUserById(uid);
}
@DeleteMapping("/users/{uid}")
public boolean deleteUserById(@PathVariable int uid){
return userSevice.deleteUser(uid);
}
@PostMapping("/users")
public boolean addUser(User user){
return userSevice.addUser(user);
}
@PutMapping("/users")
public boolean updateUserById(User user){
return userSevice.updateUser(user);
}
}