【RESTful】Yii2實現RESTful架構配置最佳實踐
Yii2實現RESTful架構配置最佳實踐
為什麼要用RESTful API
在伺服器端,應用程式狀態和功能可以分為各種資源。資源是一個有趣的概念實體,它向客戶端公開。資源的例子有:應用程式物件、資料庫記錄、演算法等等。每個資源都使用 URI (Universal Resource Identifier) 得到一個唯一的地址。所有資源都共享統一的介面,以便在客戶端和伺服器之間傳輸狀態。使用的是標準的 HTTP 方法,比如 GET、PUT、POST 和 DELETE。Hypermedia 是應用程式狀態的引擎,資源表示通過超連結互聯。
無狀態,分層,可擴充套件
本文為原創部落格,被收錄在我自己的GitHub專案中
基於Yii2的RESTful API 的實現
不用自帶的REST實現方式
首先,Yii2自帶了實現RESTful api的方式,但是,官方的例子過於簡單,把一個資源限定成了資料庫中的一個表,這顯然是和REST中定義的資源不相符的,並且實際的業務需求過於複雜,不能通過一個表進行資料的操作。
所以,我們採用了另一種方式,通過使用Yii2的不同元件,完成RESTful API的構建
路由
REST要求定義資源,採用不同HTTP方式進行訪問。
這裡用到了框架內部的路由
在專案的配置檔案/config/web.php
,中,對不同資源進行路由設定,從而達到同一個URL用不同的訪問方式來處理不同業務的目的。
//url配置對應規則
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
//配置規則,實現RESTful的方式
'POST accounts'=>'account/login', // 登入
'GET accounts'=>'account/get-avatar' , //獲取頭像
"GET accounts/status"=>'account/status', //查詢登入狀態
//獲取使用者組資訊
"GET groups"=>"account/profile",
//使用者申請加入使用者組的介面
"GET users/ask"=>"user/apply", //申請列表
"PUT users/<uid:\d+>"=>"user/pass", //通過
"PATCH users/<uid:\d+>"=>"user/nopass", //不通過
"GET users"=>"user/list", //通過的使用者列表
"DELETE users/<uid:\d+>"=>"user/remove", //移除現有的使用者
"GET users/<uid:\d+>"=>"user/info", //網紅的具體資訊
"GET users/serach"=>"user/serach", //搜尋當前使用者的使用者
//訊息中心相關
"GET notices"=>"notice/list", //訊息列表
"PUT notices/<nid:\d+>"=>"notice/mark", //訊息標記為已讀
"GET notices/status"=>"notice/status", //獲取訊息的概要
],
這部分的設計,參考官方文件對於RESTful實現的部分
- GET /users: 逐頁列出所有使用者
- HEAD /users: 顯示使用者列表的概要資訊
- POST /users: 建立一個新使用者
- GET /users/123: 返回使用者 123 的詳細資訊
- HEAD /users/123: 顯示使用者 123 的概述資訊
- PATCH /users/123 and PUT /users/123: 更新使用者123
- DELETE /users/123: 刪除使用者123
- OPTIONS /users: 顯示關於末端 /users 支援的動詞
- OPTIONS /users/123: 顯示有關末端 /users/123 支援的動詞
接收資料
我們需要獲取客戶端傳遞過來的GET
,POST
,Header
的資料,框架自帶了Yii::$app->request
,可以直接得到客戶端傳過來的資料。
參考\yii\web\Request|\yii\console\Request $request The request component. This property is read-only.
處理資料
這部分和一般的專案一樣,都用/models
中的資料表對應的Model檔案,繼承了\yii\db\ActiveRecord
的類,實現對資料表的CURD操作。
響應資料
我們在處理資料之後,需要返回給客戶端對應的資料,在REST的設計規則裡是這樣處理的
- Body只返回主要的資料,比如使用者列表,使用者的詳細資料
- Header返回其他的資訊,包括頁碼資訊,身份校驗資訊
- 完全的使用HTTP狀態碼作為資源被請求狀態的返回,比如404,403
HTTP狀態碼的說明如下
Code | HTTP Operation | Body Contents | Description |
---|---|---|---|
200 | GET,PUT | 資源 | 操作成功 |
201 | POST | 資源,元資料 | 物件建立成功 |
202 | POST,PUT,DELETE,PATCH | N/A | 請求已經被接受 |
204 | DELETE,PUT,PATCH | N/A | 操作已經執行成功,但是沒有返回資料 |
301 | GET | link | 資源已被移除 |
303 | GET | link | 重定向 |
304 | GET | N/A | 資源沒有被修改 |
400 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 引數列表錯誤(缺少,格式不匹配) |
401 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 未授權 |
403 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 訪問受限,授權過期 |
404 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 資源,服務未找到 |
405 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 不允許的http方法 |
409 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 資源衝突,或者資源被鎖定 |
415 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 不支援的資料(媒體)型別 |
429 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 請求過多被限制 |
500 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 系統內部錯誤 |
501 | GET,PSOT,PUT,DELETE,PATCH | 錯誤提示(訊息) | 介面未實現 |
格式化資料,我們的返回資料的格式為JSON
$response= Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON; //返回json
錯誤處理
通過不同的錯誤碼,返回不同的HTTP狀態碼。
由於的非常頻繁的呼叫,所以對資料進行了封裝。
錯誤處理類Error.php
/**
* 錯誤處理類
*
* ------------------------------------
*
* 錯誤處理擴充套件 seaslog
*
* http://www.oschina.net/news/50333/seaslog-0-21
*
* http://neeke.github.io/SeasLog/
*
* ------------------------------------
*
* @author Calvin
* @version 1.0
* @copyright (c) 2016,
*/
namespace app\components\error;
use Yii;
class Error {
/**
* 公共的錯誤返回處理,通過傳入引數,返回對應的錯誤程式碼,這裡也定義了錯誤返回的格式,以及對日誌的記錄
*
* @param $error_code
* @return array
*/
public static function errorJson($error_code) {
$requests = Yii::$app->request; //返回值
$post = json_encode($requests->post());
$get = json_encode($requests->get());
$headers = json_encode($requests->getHeaders()->toArray());
//帶入記錄錯誤程式碼的檔案
$error_file = require_once \Yii::$app->basePath . "/components/error/ErrorCode.php";
//獲取http狀態碼,以及文字說明
$error_info = $error_file["$error_code"];
$http_code = $error_info['http_code'];
$error_text = $error_info['remark'];
$error_body = [ //設定返回的格式
'request' => $requests->getUrl(),
'method'=>$requests->getMethod(),
'error_code' => $error_code,
'error' =>$error_text,
];
$response = Yii::$app->response;
$response->statusCode=$http_code;
$response->format = \yii\web\Response::FORMAT_JSON;
$headers = Yii::$app->response->headers;
$headers->add('X-Halo-Result', 0);
// $response->data = $error_body;
// $userIP = $requests->userIP;
//寫入日誌
// \SeasLog::error('error === {error} && error_text === {error_text} && userIP === {userIP} && post === {post} && get === {get} && header === {header} ', [
// '{error}' => $error,
// '{error_text}' => $error_file["$error"],
// '{post}' => $post,
// '{get}' => $get,
// '{userIP}' => $userIP,
// '{header}' => $headers,
// ], $request);
// $appLog = \Alibaba::AppLog();
// $appLog->debug("debug-log-emssage");
// $appLog->info("info-log-emssage");
// $appLog->warn("warn-log-emssage");
// $appLog->error("error-log-emssage");
return $error_body;
}
}
錯誤程式碼檔案ErrorCode.php
/**
* 增加對不同型別的HTTP狀態碼的返回
*
* 錯誤碼,HTTP狀態碼,返回值
*/
return [
'1001'=>[
'http_code'=>403,
'remark'=>"Token驗證失敗",
],
'1002'=>[
'http_code'=>400,
'remark'=>"引數錯誤",
],
'1003'=>[
'http_code'=>400,
'remark'=>"引數不全",
],
'2001'=>[
'http_code'=>404,
'remark'=>"使用者不存在",
],
];
呼叫錯誤資料返回
return Error::errorJson(1002);
文件
有句話說得好,程式設計師不願意寫文件,但是看到沒有文件的專案又會抓狂。。。。
概括結構
一個合格的API文件應該包含下面幾項
- 概括說明
- 加密協議
- 資料型別
- 錯誤處理
- 介面文件
- 參考資料
介面文件
介面文件告訴客戶端,呼叫什麼資料,怎麼掉,異常了咋辦。。。
- 簡單說明
- 訪問地址
- 請求方式
- 返回結果
- 返回結果欄位說明
- 錯誤程式碼
- 更新記錄
總結
RESTful API的好處在於更簡潔的規範了資料請求的方式,通過資源來設計資料介面,方便客戶端的呼叫,減少溝通成本。
不過協議畢竟只是個建議,我們可以根據自己專案的實際情況,有選擇的滿足協議的需求,更好的為自己的專案服務。
:)