用Yii2构建自己的API框架(五、2创建User接口控制器)

321 阅读3分钟

提示

本教程相关代码托管在Gitee:gitee.com/toshcn/micr…

配置公共组件

打开common/config/main.php文件,配置公共组件:

<?php
// 在公共配置添加组件项
return [
    'components' => [
        ... 
        // 配置常用工具类组件utils
        'utils' => [
            'class' => 'common\components\Utils'
        ]
    ]
];

配置api项目公共组件

打开api/config/main.php文件,配置公共组件:

<?php
// 在api项目公共配置添加组件项
return [
    'components' => [
        ... 
        // 配置接口数据统一返回格式类组件api
        'api' => [
            'class' => 'common\components\ApiResponse'
        ]
    ]
];

创建语言翻译文本

在项目common/language目录下创建目录zh-CN,在zh-CN目录创建common.php文件,文件内容如下:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

/**
 * 中文翻译文本
 * 使用方法:\Yii::t('common', 数组键名)
 */
return [
    'Please login first.' => '请先登录',
    'The Authorization is invalid.' => '访问令牌无效',
];

创建Utils组件类

在项目common\components根目录下,创建Utils.php文件,文件添加如下内容:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace common\components;

use yii\base\BaseObject;

/**
 * 公共的常用工具类组件 调用方式 \Yii::$app->utils->方法名()
 * Class Utils
 * @package common\components
 */
class Utils extends BaseObject
{
    /** @var string 缓存统一key前缀 */
    public static $cacheKeyPrefix = '__utils:';

    /**
     * 生成统一的缓存键名
     * @param string $key 缓存key
     * @return string
     */
    public static function cacheKey($key = '')
    {
        return static::$cacheKeyPrefix  . md5(__DIR__) . $key;
    }
}

创建ApiResponse接口数据格式统一返回组件

在项目api\conponents目录下,创建ApiResponse.php文件,文件添加如下内容:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace common\components;

use yii\base\BaseObject;

/**
 * Api 接口数据统一返回格式
 * @package api\components
 */
class ApiResponse extends BaseObject
{
    const ERROR = 0;    // 请求错误
    const SUCCESS = 1;  // 请求成功

    /**
     * @var int 错误码
     * 错误码建议用下面规则
     * 0 接口错误 1 接口成功 >1为详细错误
     * 权限错误: 1000-1999
     * 资源错误: 3000-3999
     * 请求参数错误: 4000-4999
     * 服务器错误: 5000-5999
     */
    private $_errCode = 0;

    /**
     * @var string 错误码对应提示说明.
     */
    private $_message = 'success';

    /**
     * 状态码及其对应描述文本
     * @var array
     */
    private $_apiStatusesMessage = [
        0 => 'error',
        1 => 'success'
    ];

    /**
     * 设置Api 错误码
     * @param int $value 错误码
     * @param string $text 错误码描述文本
     */
    public function setErrCode($value, $text = null)
    {
        $this->_errCode = (int) $value;
        if ($text === null) {
            $this->_message = !empty($this->_apiStatusesMessage[$this->_errCode])
                ? $this->_apiStatusesMessage[$this->_errCode]
                : '';
        } else {
            $this->_message = $text;
        }
    }

    /**
     * 接口请求成功
     *
     * @param array $data 要返回的数据内容
     * @param string $text 状态码描述文本
     * @return array
     */
    public function success($data = [], $text = null)
    {
        $this->setErrCode(static::SUCCESS, $text);
        return [
            'status' => static::SUCCESS,
            'code' => static::SUCCESS,
            'message' => $this->_message,
            'data' => $data,
        ];
    }

    /**
     * 接口请求错误
     *
     * @param int $code 错误码
     * @param array $data 要返回的数据内容
     * @param string $text 错误码描述文本
     * @return array
     */
    public function error($code, $text = null, $data = [])
    {
        $this->setErrCode($code, $text);
        return [
            'status' => static::ERROR,
            'code' => $this->_errCode,
            'message' => $this->_message,
            'data' => $data
        ];
    }
}

创建ApiController接口公共基类控制器

在项目api\controllers目录下,创建ApiController.php文件,文件添加如下内容:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace api\controllers;

use yii\rest\Controller;
use yii\filters\Cors;
use yii\helpers\ArrayHelper;

/**
 * API 项目基类控制器 api项目所有接口控制器都要继承此类
 * Class ApiController
 * @package api\controllers
 */
class ApiController extends Controller
{
    /**
     * 配置控制器行为
     * @return array
     */
    public function behaviors()
    {
        $behaviors = ArrayHelper::merge([
            'corsFilter' => [
                'class' => Cors::class,
                'cors' => [
                    'Origin' => ['*'], // 跨域配置 *允许全部域名
                    // 可过滤请求的动作类型 如: 可配置只允许POST和GET
                    'Access-Control-Request-Methods' => ['POST', 'PUT', 'GET', 'OPTIONS'],
                    'Access-Control-Request-Headers' => ['*']
                ]
            ]
        ], parent::behaviors());
        // 是否在HTTP头带上目前的速率限制信息
        $behaviors['rateLimiter']['enableRateLimitHeaders'] = false;
        return $behaviors;
    }

    /**
     * 重载请求动作方法前
     * 可在此处做一些代码检查,比如网站是否关闭,用户是否登录
     * @param mixed $action 当前请求的动作
     * @return bool
     * @throws \yii\web\BadRequestHttpException
     */
    public function beforeAction($action)
    {
        $res = parent::beforeAction($action);

        // 检测网站是否关闭
        // todo
        return $res;
    }
}

创建AuthController认证接口公共基类控制器

在项目api\controllers目录下,创建AuthController.php文件,文件添加如下内容:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace api\controllers;

use Yii;
use yii\filters\auth\HttpBearerAuth;

/**
 * API项目认证类控制器 api项目需要用户登录的接口的控制器都要继承此类
 * Class AuthController
 * @package api\controllers
 */
class AuthController extends ApiController
{
    // 错误码 令牌无效
    const ERR_CODE_AUTHORIZATION_INVALID = 3002;
    // 错误码 未登录
    const ERR_CODE_NOT_LOGGED_IN = 3001;
    /**
     * 在请求动作前检测会员登录状态
     * @param mixed $action 当前请求的动作
     * @return bool
     * @throws \yii\web\BadRequestHttpException
     */
    public function beforeAction($action)
    {
        $res = parent::beforeAction($action);

        // 检测会员登录状态 如果用户未登录 取出请求标头 使用标头保存的token登录用户账号
        if ($res && Yii::$app->getUser()->isGuest) {
            $auth = new HttpBearerAuth();
            // 获取PHP请求标头:Authorization
            $authHeader = Yii::$app->getRequest()->getHeaders()->get($auth->header);
            if ($auth->pattern !== null) {
                // 用正则取出标头 保存在变量$matches中,$matches下标1为token的值
                if (preg_match($auth->pattern, $authHeader, $matches)) {
                    $authHeader = empty($matches[1]) ? false : $matches[1];
                    // 如果Authorization标头不为空,尝试用token登录用户账号
                    if ($authHeader && Yii::$app->getUser()->loginByAccessToken($authHeader, get_class($auth))) {
                        // 登录成功
                        return true;
                    }
                    // 登录令牌无效
                    Yii::$app->getResponse()->data = Yii::$app->api->error(
                        static::ERR_CODE_AUTHORIZATION_INVALID,
                        Yii::t('common', 'The Authorization is invalid.')
                    );
                    Yii::$app->getResponse()->send();
                    return false;
                }
            }
            // 未登录
            Yii::$app->getResponse()->data = Yii::$app->api->error(
                static::ERR_CODE_NOT_LOGGED_IN,
                Yii::t('common', 'Please login first.')
            );
            Yii::$app->getResponse()->send();
        }
        // 禁止未登录访问接口
        return false;
    }
}

修改TestController控制器

在项目api\controllers目录下,修改TestController.php文件,文件修改如下:

<?php
/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/14 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace api\controllers;

/**
 * 测试控制器类
 * Class TestController
 * @package api\controllers
 */
class TestController extends AuthController
{
    /**
     * 测试动作
     * @return array
     */
    public function actionIndex()
    {
        return \Yii::$app->api->error();
    }
}

修改User模型命令空间

打开common/models/User.php文件,修改如下:

...
namespace common\modules; // 原内容
namespace common\models;  // 修改为
...

访问test控制器

打开浏览器,在地址栏输入www.mysite.local/test/index mysite.local 替换为实际的主机名,将会看到输出xml如下内容:

<?xml version="1.0" encoding="utf-8"?>
<response>
    <status>0</status>
    <code>3001</code>
    <message>请先登录</message>
    <data/>
</response>

用Postman模拟请求,设置请求标头content-typeapplication/json; charset=UTF-8, 设置请求标头Authorization,将会看到如下内容:

{
    "status": 0,
    "code": 3002,
    "message": "令牌无效",
    "data": []
}

修改语言配置

打开common/config/main.php文件,修改如下:

    ...
    //'language' => 'zh-CN',         // 设置目标语言 注释语言配置,或配置为en-US
    ...

再次访问test控制器,你将看到接口返回的message为英文。

OK现在创建User接口控制器

打开api/modules/v1/controllers目录,创建UserController.php文件,文件内容如下:

<?php /** @noinspection ALL */

/**
 * @link https://gitee.com/toshcn/micro-hau
 * @copyright Copyright (c) 2022/4/20 micro-hau
 * @author toshcn <toshcn@foxmail.com>
 */

namespace api\modules\v1\controllers;

use api\controllers\ApiController;

/**
 * 用户接口控制器
 * Class UserController
 * @package api\modules\v1\controllers
 */
class UserController extends ApiController
{
    /**
     * @return mixed
     */
    public function actionIndex()
    {
        return \Yii::$app->api->success(['id' => 1, 'nickname' => '测试用户']);
    }
}

访问user控制器

打开浏览器,在地址栏输入www.mysite.local/v1/user/ind… mysite.local 替换为实际的主机名,将会看到输出xml如下内容:

<?xml version="1.0" encoding="utf-8"?>
<response>
    <status>1</status>
    <code>1</code>
    <message>success</message>
    <data>
        <id>1</id>
        <nickname>测试用户</nickname>
    </data>
</response>

用Postman模拟请求,设置请求标头content-typeapplication/json; charset=UTF-8,将会看到如下内容:

{
    "status": 1,
    "code": 1,
    "message": "success",
    "data": {
        "id": 0,
        "nickname": "测试用户"
    }
}