最近在研究如何利用 yii2 搭建 restful api,將 yii2 restful api / yii2 rest api 搭建心得寫下咽斧,歡迎一起討論
使用yii2.0.13 advanced 版阅束,將 frontend 整個作為 api 接口項目呼胚,除了接口的路由規(guī)則可以認證通過外,其他的路由規(guī)則都返回請求錯誤的格式
1息裸、數(shù)據(jù)庫結(jié)構(gòu)
CREATE TABLE `goods` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`price` int(11) unsigned NOT NULL,
`status` tinyint(1) unsigned NOT NULL,
`create_time` int(11) unsigned NOT NULL,
`modify_time` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2蝇更、使用 gii 創(chuàng)建 goods model
3、創(chuàng)建 api modules
在 frontend 下新建文件夾 modules
使用 gii 在 modules 文件中創(chuàng)建 v1 module(防止以后接口更新替換時向前兼容,接口增加 v1 v2 等版本控制)
4呼盆、將 v1 moduel 寫到配置文件中
'modules' => [
'v1' => [
'class' => 'frontend\modules\v1\Module',
],
],
5年扩、修改 frontend 下 main.php 中,user 的配置(以下說的配置文件访圃,都是 frontend 下 main.php)
'user' => [
'identityClass' => 'frontend\models\User',
'enableAutoLogin' => false,
'enableSession' => false,
'loginUrl' => null,
],
6厨幻、新建 frontend\models\User,繼承 common\models\User
<?php
namespace frontend\models;
class User extends \common\models\User
{
}
7腿时、啟用并修改配置文件中的 urlManager
調(diào)試 urlManager 的時候要小心况脆,他會將生成好的路由寫入緩存(默認是文件緩存),有些更改可能不會立馬生效
'urlManager' => [
//用于表明 urlManager 是否啟用 URL 美化功能
//默認不啟用批糟。但實際使用中格了,特別是產(chǎn)品環(huán)境,一般都會啟用
'enablePrettyUrl' => true,
//是否啟用嚴格解析徽鼎,如啟用嚴格解析盛末,要求當前請求應(yīng)至少匹配1個路由規(guī)則弹惦,否則認為是無效路由。
//這個選項僅在 enablePrettyUrl 啟用后才有效悄但。
//如果開啟棠隐,表示只有配置在 rules 里的規(guī)則才有效
//由于項目會將一些 url 進行優(yōu)化,所以這里需要設(shè)置為 true
'enableStrictParsing' => true,
//指定是否在URL在保留入口腳本 index.php
'showScriptName' => false,
'rules' => [
//當然算墨,如果自帶的路由無法滿足需求宵荒,可以自己增加規(guī)則
'GET <module:(v)\d+>/<controller:\w+>/search' => '<module>/<controller>/search',
[
'class' => 'yii\rest\UrlRule',
'controller' => ['v1/goods'],
// 由于 resetful 風(fēng)格規(guī)定 URL 保持格式一致并且始終使用復(fù)數(shù)形式
// 所以如果你的 controller 是單數(shù)的名稱比如 UserController
// 設(shè)置 pluralize 為 true (默認為 true)的話,url 地址必須是 users 才可訪問
// 如果 pluralize 設(shè)置為 false, url 地址必須是 user 也可訪問
// 如果你的 controller 本身是復(fù)數(shù)名稱 UsersController 净嘀,此參數(shù)沒用报咳,url 地址必須是 users
'pluralize' => false,
],
],
],
8、去掉配置文件中的 errorHandler 配置(整個 frontend 都是接口挖藏,不需要 html 的響應(yīng)格式)
9暑刃、將內(nèi)容協(xié)商配置到引導(dǎo)文件中(因為整個 frontend 都需要)
'bootstrap' => [
'log',
//全局內(nèi)容協(xié)商
[
//ContentNegotiator 類可以分析request的header然后指派所需的響應(yīng)格式給客戶端,不需要我們?nèi)斯ぶ付? 'class' => 'yii\filters\ContentNegotiator',
'formats' => [
'application/json' => yii\web\Response::FORMAT_JSON,
'application/xml' => yii\web\Response::FORMAT_XML,
//api 端目前只需要json 和 xml
//還可以增加 yii\web\Response 類內(nèi)置的響應(yīng)格式膜眠,或者自己增加響應(yīng)格式
],
]
],
10岩臣、配置文件中,components 配置 response宵膨,返回格式
'response' => [
'class' => 'yii\web\Response',
//設(shè)置 api 返回格式,錯誤碼不在 header 里實現(xiàn)架谎,而是放到 body里
'as resBeforeSend' => [
'class' => 'frontend\extensions\ResBeforeSendBehavior',
'defaultCode' => 500,
'defaultMsg' => 'error',
],
//ps:components 中綁定事件,可以用兩種方法
//'on eventName' => $eventHandler,
//'as behaviorName' => $behaviorConfig,
//參考 http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html#configuration-format
],
11辟躏、編寫 frontend\extensions\ResBeforeSendBehavior 代碼
<?php
namespace frontend\extensions;
use Yii;
use yii\web\Response;
use yii\base\Behavior;
class ResBeforeSendBehavior extends Behavior{
public $defaultCode = 500;
public $defaultMsg = 'error';
// 重載events() 使得在事件觸發(fā)時谷扣,調(diào)用行為中的一些方法
public function events() {
// 在 EVENT_BEFORE_SEND 事件觸發(fā)時,調(diào)用成員函數(shù) beforeSend
return [
Response::EVENT_BEFORE_SEND => 'beforeSend',
];
}
// 注意 beforeSend 是行為的成員函數(shù)捎琐,而不是綁定的類的成員函數(shù)会涎。
// 還要注意,這個函數(shù)的簽名瑞凑,要滿足事件 handler 的要求末秃。
public function beforeSend($event)
{
try {
$response = $event->sender;
if($response->data === null){
$response->data = [
'code' => $this->defaultCode,
'msg' => $this->defaultMsg,
];
} elseif(!$response->isSuccessful) {
$exception = Yii::$app->getErrorHandler()->exception;
if(is_object($exception) && !$exception instanceof yii\web\HttpException){
throw $exception;
} else {
$rData = $response->data;
$response->data = [
'code' => empty($rData['status']) ? $this->defaultCode : $rData['status'],
'msg' => empty($rData['message']) ? $this->defaultMsg : $rData['message'],
];
}
} else {
/**
* $response->isSuccessful 表示是否會拋出異常
* 值為 true, 代表返回數(shù)據(jù)正常,沒有拋出異常
*/
$rData = $response->data;
$response->data = [
'code' => isset($rData['error_code']) ? $rData['error_code'] : 0,
'msg' => isset($rData['res_msg']) ? $rData['res_msg'] : $rData,
];
$response->statusCode = 200;
}
} catch (\Exception $e) {
$response->data = [
'code' => $this->defaultCode,
'msg' => $this->defaultMsg,
];
}
return true;
}
}
12籽御、創(chuàng)建 GoodsController.php
<?php
namespace frontend\modules\v1\controllers;
use yii\rest\ActiveController;
class GoodsController extends ActiveController
{
public $modelClass = 'common\models\Goods';
public function actionSearch(){
return [
'error_code' => 20,
'res_msg' => 'ok',
];
}
}
13练慕、應(yīng)用入口同級增加.htaccess文件,隱藏index.php篱蝇,以apache為例
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php
14贺待、測試
命令:
curl -s -H Accept:application/xml http://local.rest.com/v1/goods/1
返回:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<code>0</code>
<msg>
<id>1</id>
<name>測試商品1</name>
<price>600</price>
<status>1</status>
<create_time>1520490595</create_time>
<modify_time>1520490595</modify_time>
</msg>
</response>
命令:
curl -s -H Accept:application/json http://local.rest.com/v1/goods/1
返回:
{
"code":0,
"msg":{
"id":"1",
"name":"測試商品1",
"price":"600",
"status":1,
"create_time":"1520490595",
"modify_time":"1520490595"
}
}
命令:
curl -s -H Accept:application/json http://local.rest.com/v1/goods11
返回:
{"code":404,"msg":"Page not found."}
命令:
curl -s -H Accept:application/json http://local.rest.com/v1/goods/search
返回:
{"code":20,"msg":"ok"}
15、參考
http://www.yiichina.com/doc/guide/2.0/rest-quick-start
http://www.yiichina.com/doc/guide/2.0/runtime-handling-errors
http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html#configuration-format
http://www.yii-china.com/post/detail/536.html