美文网首页Yii2PHP经验分享yii2
yii2 restful 风格搭建(一)

yii2 restful 风格搭建(一)

作者: smoke_zl | 来源:发表于2018-03-13 21:12 被阅读188次

    最近在研究 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
    <?php
    
    namespace 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 代码
    <?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() 使得在事件触发时,调用行为中的一些方法
        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
    <?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、应用入口同级增加.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

    相关文章

      网友评论

        本文标题:yii2 restful 风格搭建(一)

        本文链接:https://www.haomeiwen.com/subject/hkutqftx.html