继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

yii2 restful 风格搭建(一)

RISEBY
关注TA
已关注
手记 309
粉丝 70
获赞 317

最近在研究 yii2 如何搭建 restful api,将心得写下,欢迎一起讨论
使用yii2.0.13 advanced 版,将 frontend 整个作为 api 接口项目,除了接口的路由规则可以认证通过外,其他的路由规则都返回请求错误的格式

1、数据库结构
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 创建 goods model
3、创建 api modules

在 frontend 下新建文件夹 modules
使用 gii 在 modules 文件中创建 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
<?phpnamespace frontend\models;class User extends \common\models\User{

}
7、启用并修改配置文件中的 urlManager

调试 urlManager 的时候要小心,他会将生成好的路由写入缓存(默认是文件缓存),有些更改可能不会立马生效

'urlManager' => [    //用于表明 urlManager 是否启用 URL 美化功能
    //默认不启用。但实际使用中,特别是产品环境,一般都会启用
    'enablePrettyUrl'       => true,    //是否启用严格解析,如启用严格解析,要求当前请求应至少匹配1个路由规则,否则认为是无效路由。
    //这个选项仅在 enablePrettyUrl 启用后才有效。
    //如果开启,表示只有配置在 rules 里的规则才有效
    //由于项目会将一些 url 进行优化,所以这里需要设置为 true
    'enableStrictParsing'   => true,    //指定是否在URL在保留入口脚本 index.php
    'showScriptName'        => false,    'rules' => [        //当然,如果自带的路由无法满足需求,可以自己增加规则
        'GET <module:(v)\d+>/<controller:\w+>/search' => '<module>/<controller>/search',
        [            'class'         => 'yii\rest\UrlRule',            'controller'    => ['v1/goods'],            // 由于 resetful 风格规定 URL 保持格式一致并且始终使用复数形式
            // 所以如果你的 controller 是单数的名称比如 UserController
            // 设置 pluralize 为 true (默认为 true)的话,url 地址必须是 users 才可访问
            // 如果 pluralize 设置为 false, url 地址必须是 user 也可访问
            // 如果你的 controller 本身是复数名称 UsersController ,此参数没用,url 地址必须是 users
            'pluralize'     => false,
        ],
    ],
],
8、去掉配置文件中的 errorHandler 配置(整个 frontend 都是接口,不需要 html 的响应格式)
9、将内容协商配置到引导文件中(因为整个 frontend 都需要)
'bootstrap' => [    'log',    //全局内容协商
    [        //ContentNegotiator 类可以分析request的header然后指派所需的响应格式给客户端,不需要我们人工指定
        '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 类内置的响应格式,或者自己增加响应格式
        ],
    ]
],
10、配置文件中,components 配置 response,返回格式
'response' => [    'class'     => 'yii\web\Response',    //设置 api 返回格式,错误码不在 header 里实现,而是放到 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 代码
<?phpnamespace frontend\extensions;use Yii;use yii\web\Response;use yii\base\Behavior;class ResBeforeSendBehavior extends Behavior{    public $defaultCode = 500;    public $defaultMsg = 'error';    // 重载events() 使得在事件触发时,调用行为中的一些方法
    public function events() {        // 在 EVENT_BEFORE_SEND 事件触发时,调用成员函数 beforeSend
        return [
            Response::EVENT_BEFORE_SEND => 'beforeSend',
        ];
    }    // 注意 beforeSend 是行为的成员函数,而不是绑定的类的成员函数。
    // 还要注意,这个函数的签名,要满足事件 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, 代表返回数据正常,没有抛出异常
                 */
                $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、创建 GoodsController.php
<?phpnamespace 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、应用入口同级增加.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



作者:smoke_zl
链接:https://www.jianshu.com/p/74d5dbb8af5e

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP