基于 Yii 2 的 HTTP 客户端扩展的响应处理的现阶段时间内的最佳实践(在之前的实现上有所优化,在后续一段时间内皆如此实践,HTTP 客户端组件的本地化,返回的处理逻辑的简化等)

1、获取菜单列表,如图1

图1

{
    "code": 10000,
    "message": "获取菜单列表成功",
    "data": {
        "items": [
            {
                "id": "974b2b64aac24973dbd39b40fb2cc880",
                "item_title": "文章审核",
                "item_icon": "https://cmcconsole.chinamcloud.com/imgs/service_side_icon/cmcp/content-audits.png",
                "item_link": "",
                "item_desc": "",
                "item_type": "category",
                "item_sort": "1",
                "item_pid": "0",
                "item_target": "0",
                "is_iframe": "1",
                "children": []
            },
            {
                "id": "61600e1530e7671346fe6e436195f4b7",
                "item_title": "平台管控",
                "item_icon": "https://cmcconsole.chinamcloud.com/imgs/service_side_icon/cmcp/plat_cont.png",
                "item_link": "",
                "item_desc": "",
                "item_type": "category",
                "item_sort": "2",
                "item_pid": "0",
                "item_target": "0",
                "is_iframe": "1",
                "children": []
            },
            {
                "id": "66c8e5ce3261710ccc90841141939c92",
                "item_title": "设置",
                "item_icon": "https://cmcconsole.chinamcloud.com/imgs/service_side_icon/cmcp/set_conf.png",
                "item_link": "",
                "item_desc": "",
                "item_type": "category",
                "item_sort": "3",
                "item_pid": "0",
                "item_target": "0",
                "is_iframe": "1",
                "children": []
            }
        ],
        "_links": {
            "self": {
                "href": "http://api.gitlab-php-yii2-app-advanced-cmc.localhost/v1/menus?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=0c4dba79f6028dcfc519917a45b98bba&page=1"
            }
        },
        "_meta": {
            "totalCount": 3,
            "pageCount": 1,
            "currentPage": 1,
            "perPage": 20
        }
    }
}

2、查看 Available Debug Data,其数据来源于 HTTP,如图2

图2

GET https://cmcconsole.flydev.chinamcloud.cn/nav-bar/service-side-bar?service_key=cmcp
Cookie: login_chinamcloud_id=2e368664c41b8bf511bcc9c65d86dbc3; login_chinamcloud_tid=0c4dba79f6028dcfc519917a45b98bba

3、查看 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,代码如下

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2018/02/28
 * Time: 13:14
 */
namespace common\logics\http\cmc_console;

use Yii;
use yii\web\HttpException;
use yii\web\ServerErrorHttpException;

/**
 * 框架服务控制台的菜单
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */class Menu extends Model
{
    public $service_key;
    public $login_id;
    public $login_tid;

    public function rules()
    {
        return [
            // login_id、login_tid 属性必须有值
            [['login_id', 'login_tid'], 'required'],
        ];
    }

    public function attributeLabels()
    {
        return [
            'service_key' => \Yii::t('model/http/cmc-console/menu', 'Service Key'),
            'login_id' => \Yii::t('model/http/cmc-console/menu', 'Login Id'),
            'login_tid' => \Yii::t('model/http/cmc-console/menu', 'Login Tid'),
        ];
    }

    /**
     * 返回模块的菜单信息
     *
     * @param string $loginId 用户标识
     * @param string $loginTid 登录标识
     *
     * @return array|bool
     *
     * 格式如下:
     *
     * 框架服务控制台的菜单信息
     * [
     *     'message' => '', //说明
     *     'data' => [], //数据
     * ]
     *
     * 失败(将错误保存在 [[yii\base\Model::errors]] 属性中)
     * false
     *
     * @throws ServerErrorHttpException 如果响应状态码不等于20x
     * @throws HttpException 如果登录超时
     */    public function getMenu($loginId, $loginTid)
    {
        $this->service_key = Yii::$app->params['cmcConsole']['serviceKey'];
        $this->login_id = $loginId;
        $this->login_tid = $loginTid;
        $cookie = 'login_chinamcloud_id=' . $this->login_id . '; login_chinamcloud_tid=' . $this->login_tid . '';

        $response = Yii::$app->cmcConsoleHttp->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        // 检查响应状态码是否等于20x
        if ($response->isOk) {
            // 检查业务逻辑是否成功
            if ($response->data['code'] === 10000) {
                $cmcConsoleData = ['message' => $response->data['message'], 'data' => $response->data['data']['menu_data']];
                return $cmcConsoleData;
            } elseif ($response->data['code'] === 99998) {
                // 登录超时
                throw new HttpException(302, Yii::t('error', Yii::t('error', Yii::t('error', '201003'), ['message' => $response->data['message']])), 201003);
            } else {
                $this->addError('service_key', $response->data['message']);
                return false;
            }
        } else {
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201001'), ['status_code' => $response->statusCode])), 201001);
        }
    }
}

4、cmcConsoleHttp 是一个组件,通过应用组件配置 HTTP 客户端,参考网址:https://www.yiiframework.com/extension/yiisoft/yii2-httpclient/doc/guide/2.0/zh-cn/usage-setup-client-instance ,查看配置文件:common/config/main-local.php

        'cmcConsoleHttp' => [
            'class' => 'yii\httpclient\Client',
            'baseUrl' => 'https://cmcconsole.flydev.chinamcloud.cn',
            'transport' => 'yii\httpclient\CurlTransport'
        ],

5、查看参数文件:common/config/params-local.php,存在与 HTTP 客户端相关的配置参数

    // 框架服务控制台
    'cmcConsole' => [
        'hostInfo' => 'https://cmcconsole.flydev.chinamcloud.cn', // HOME URL
        'baseUrl' => '', // BASE URL
        'appKey' => 'assZdqfgOXcIFDvG', // 模块Key
        'appSecret' => 'sd3fe4GDSRqrl7mLFyP7ogbk1pDFwzT', // 模块Secret
        'serviceKey' => 'cmcp', // 服务标识
    ],

6、查看方法文件:api/rests/menu/IndexAction.php,调用 HTTP 模型的方法:getMenu,代码如下

            // 所有输入数据都有效,获取模块的菜单信息
            $menu = $model->getMenu($model->login_id, $model->login_tid);

            if ($menu === false) {
                if ($model->hasErrors()) {
                    $firstError = '';
                    foreach ($model->getFirstErrors() as $message) {
                        $firstError = $message;
                        break;
                    }
                    throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '226020'), ['first_error' => $firstError])), 226020);
                } elseif (!$model->hasErrors()) {
                    throw new ServerErrorHttpException('Authority Center HTTP requests fail for unknown reasons.');
                }
            }

7、现阶段的实现,存在 4 个问题,如图3
(1)当应用中需要基于 HTTP 调用多个服务时,应用组件的数量会持续地增加,请谨慎注册太多应用组件,应用组件就像全局变量,使用太多可能加大测试和维护的难度。一般情况下可以在需要时再创建本地组件。
(2)新增加一个 HTTP 组件时,需要同时在配置文件:common/config/main-local.php、common/config/params-local.php,有所重复,冗余了些。
(3)当响应状态码不等于20x时,认为调用失败(绝大部份情况下,此业务逻辑成立)。抛出服务器错误异常,此时,错误异常信息不够完善,一旦调用失败,很难排查具体错误原因。
(4)调用 HTTP 模型的方法时,对于返回的处理逻辑,过于复杂,显得冗余了些,需要有所精简。

图3

8、先解决第 1 个问题,参考网址:https://www.yiiframework.com/extension/yiisoft/yii2-httpclient/doc/guide/2.0/zh-cn/usage-setup-client-instance ,将 yii\httpclient\Client 实例封装为本地组件

9、查看继承关系:yii\httpclient\Client » yii\base\Component,common\logics\http\cmc_console\Menu » common\logics\http\cmc_console\Model » \yii\base\Model » yii\base\Component,因此,可在模型:common\logics\http\cmc_console\Model 中将 yii\httpclient\Client 实例封装为本地组件,编辑 common/logics/http/cmc_console/Model.php,创建 HTTP 客户端对象

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2018/02/28
 * Time: 13:14
 */
namespace common\logics\http\cmc_console;

use Yii;
use yii\base\InvalidConfigException;
use yii\httpclient\Client;
use yii\httpclient\CurlTransport;

/**
 * 框架服务控制台的基础类
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since 1.0
 */class Model extends \yii\base\Model
{
    private $_httpClient;

    /*
     * 创建 HTTP 客户端对象
     *
     * @return object the created object
     * @throws InvalidConfigException if a registered parser does not implement the [[RequestParserInterface]].
     */    public function getHttpClient()
    {
        if (!is_object($this->_httpClient)) {
            $this->_httpClient = Yii::createObject([
                'class' => Client::className(),
                'baseUrl' => Yii::$app->params['cmcConsole']['hostInfo'] . Yii::$app->params['cmcConsole']['baseUrl'],
                'transport' => CurlTransport::className(),
            ]);
        }
        return $this->_httpClient;
    }
}

10、编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,Yii::$app->cmcConsoleHttp 替换为 $this->httpClient

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();

11、编辑配置文件:common/config/main-local.php,删除组件:cmcConsoleHttp

12、获取菜单列表,仍然是可正常获取,查看 Available Debug Data,其数据来源于 HTTP,请求无变化,如图4

图4

13、此时,前 2 个问题皆已经得到解决,先解决第 3 个问题,调用 HTTP 模型的方法时,对于返回的处理逻辑,过于复杂,显得冗余了些,需要有所精简。编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,当响应状态码等于 500 时,即不等于20x时,认为调用失败(绝大部份情况下,此业务逻辑成立)。打印响应对象

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar-1')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        print_r($response);
        exit;
yii\httpclient\Response Object
(
    [client] => yii\httpclient\Client Object
        (
            [baseUrl] => https://cmcconsole.flydev.chinamcloud.cn
            [formatters] => Array
                (
                    [urlencoded] => yii\httpclient\UrlEncodedFormatter Object
                        (
                            [encodingType] => 1
                            [charset] => 
                        )

                )

            [parsers] => Array
                (
                )

            [requestConfig] => Array
                (
                )

            [responseConfig] => Array
                (
                )

            [contentLoggingMaxSize] => 2000
            [_transport:yii\httpclient\Client:private] => yii\httpclient\CurlTransport Object
                (
                    [_events:yii\base\Component:private] => Array
                        (
                        )

                    [_eventWildcards:yii\base\Component:private] => Array
                        (
                        )

                    [_behaviors:yii\base\Component:private] => 
                )

            [_events:yii\base\Component:private] => Array
                (
                )

            [_eventWildcards:yii\base\Component:private] => Array
                (
                )

            [_behaviors:yii\base\Component:private] => Array
                (
                )

        )

    [_headers:yii\httpclient\Message:private] => Array
        (
            [0] => HTTP/1.1 500 Internal Server Error
            [1] => Server: nginx
            [2] => Date: Wed, 11 Dec 2019 05:59:37 GMT
            [3] => Content-Type: text/html; charset=UTF-8
            [4] => Transfer-Encoding: chunked
            [5] => Connection: keep-alive
            [6] => Access-Control-Allow-Origin: 
            [7] => Access-Control-Allow-Methods: *
            [8] => Access-Control-Allow-Credentials: true
            [9] => Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
        )

    [_cookies:yii\httpclient\Message:private] => 
    [_content:yii\httpclient\Message:private] => <pre>An Error occurred while handling another error:
yii\base\InvalidRouteException: Unable to resolve the request &quot;site/error&quot;. in /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php:537
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/web/ErrorHandler.php(97): yii\base\Module-&gt;runAction(&#039;site/error&#039;)
#1 /home/www/cmc_console/vendor/yiisoft/yii2/base/ErrorHandler.php(111): yii\web\ErrorHandler-&gt;renderException(Object(yii\web\NotFoundHttpException))
#2 /home/www/cmc_console/vendor/sentry/Raven/ErrorHandler.php(86): yii\base\ErrorHandler-&gt;handleException(Object(yii\web\NotFoundHttpException))
#3 [internal function]: Raven_ErrorHandler-&gt;handleException(Object(yii\web\NotFoundHttpException))
#4 {main}
Previous exception:
yii\base\InvalidRouteException: Unable to resolve the request: nav-bar/service-side-bar-1 in /home/www/cmc_console/vendor/yiisoft/yii2/base/Controller.php:143
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php(528): yii\base\Controller-&gt;runAction(&#039;service-side-ba...&#039;, Array)
#1 /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php(103): yii\base\Module-&gt;runAction(&#039;nav-bar/service...&#039;, Array)
#2 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application-&gt;handleRequest(Object(yii\web\Request))
#3 /home/www/cmc_console/web/index.php(13): yii\base\Application-&gt;run()
#4 {main}

Next yii\web\NotFoundHttpException: 页面未找到。 in /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php:115
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application-&gt;handleRequest(Object(yii\web\Request))
#1 /home/www/cmc_console/web/index.php(13): yii\base\Application-&gt;run()
#2 {main}</pre>
    [_data:yii\httpclient\Message:private] => 
    [_format:yii\httpclient\Message:private] => 
    [_events:yii\base\Component:private] => Array
        (
        )

    [_eventWildcards:yii\base\Component:private] => Array
        (
        )

    [_behaviors:yii\base\Component:private] => 
)

14、编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,当响应状态码等于 500 时,即不等于20x时,认为调用失败(绝大部份情况下,此业务逻辑成立)。打印响应数据

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar-1')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        print_r($response->data);
        exit;
Array
(
    [0] => An Error occurred while handling another error:
yii\base\InvalidRouteException: Unable to resolve the request "site/error". in /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php:537
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/web/ErrorHandler.php(97): yii\base\Module->runAction('site/error')
#1 /home/www/cmc_console/vendor/yiisoft/yii2/base/ErrorHandler.php(111): yii\web\ErrorHandler->renderException(Object(yii\web\NotFoundHttpException))
#2 /home/www/cmc_console/vendor/sentry/Raven/ErrorHandler.php(86): yii\base\ErrorHandler->handleException(Object(yii\web\NotFoundHttpException))
#3 [internal function]: Raven_ErrorHandler->handleException(Object(yii\web\NotFoundHttpException))
#4 {main}
Previous exception:
yii\base\InvalidRouteException: Unable to resolve the request: nav-bar/service-side-bar-1 in /home/www/cmc_console/vendor/yiisoft/yii2/base/Controller.php:143
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php(528): yii\base\Controller->runAction('service-side-ba...', Array)
#1 /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php(103): yii\base\Module->runAction('nav-bar/service...', Array)
#2 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application->handleRequest(Object(yii\web\Request))
#3 /home/www/cmc_console/web/index.php(13): yii\base\Application->run()
#4 {main}

Next yii\web\NotFoundHttpException: 页面未找到。 in /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php:115
Stack trace:
#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\web\Application->handleRequest(Object(yii\web\Request))
#1 /home/www/cmc_console/web/index.php(13): yii\base\Application->run()
#2 {main}
)

15、编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,当响应状态码等于 500 时,即不等于20x时,认为调用失败(绝大部份情况下,此业务逻辑成立)。抛出服务器错误异常,此时,错误异常信息不够完善,一旦调用失败,很难排查具体错误原因

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar-1')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        // 检查响应状态码是否等于20x
        if ($response->isOk) {
            // 检查业务逻辑是否成功
            if ($response->data['code'] === 10000) {
                $cmcConsoleData = ['message' => $response->data['message'], 'data' => $response->data['data']['menu_data']];
                return $cmcConsoleData;
            } elseif ($response->data['code'] === 99998) {
                // 登录超时
                throw new HttpException(302, Yii::t('error', Yii::t('error', Yii::t('error', '201003'), ['message' => $response->data['message']])), 201003);
            } else {
                $this->addError('service_key', $response->data['message']);
                return false;
            }
        } else {
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201001'), ['status_code' => $response->statusCode])), 201001);
        }
{
    "name": "Internal Server Error",
    "message": "框架服务控制台HTTP请求失败,状态码:500",
    "code": 201001,
    "status": 500,
    "type": "yii\\web\\ServerErrorHttpException"
}

16、编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,当响应状态码等于 500 时,即不等于20x时,认为调用失败(绝大部份情况下,此业务逻辑成立)。抛出服务器错误异常,完善错误异常信息,一旦调用失败,可以更为容易地排查具体错误原因,如图5

图5

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar-1')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        // 检查响应状态码是否等于20x
        if ($response->isOk) {
            // 检查业务逻辑是否成功
            if ($response->data['code'] === 10000) {
                $cmcConsoleData = ['message' => $response->data['message'], 'data' => $response->data['data']['menu_data']];
                return $cmcConsoleData;
            } elseif ($response->data['code'] === 99998) {
                // 登录超时
                throw new HttpException(302, Yii::t('error', Yii::t('error', Yii::t('error', '201003'), ['message' => $response->data['message']])), 201003);
            } else {
                $this->addError('service_key', $response->data['message']);
                return false;
            }
        } else {
            $code = isset($response->data['code']) ? $response->data['code'] : 0; // 返回码
            $message = isset($response->data[0]) ? $response->data[0] : ''; // 说明
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201001'), ['status_code' => $response->statusCode, 'code' => $code, 'message' => $message])), 201001);
        }
{
    "name": "Internal Server Error",
    "message": "框架服务控制台HTTP请求失败,状态码:500,返回码:0,说明:An Error occurred while handling another error:\nyii\\base\\InvalidRouteException: Unable to resolve the request \"site/error\". in /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php:537\nStack trace:\n#0 /home/www/cmc_console/vendor/yiisoft/yii2/web/ErrorHandler.php(97): yii\\base\\Module->runAction('site/error')\n#1 /home/www/cmc_console/vendor/yiisoft/yii2/base/ErrorHandler.php(111): yii\\web\\ErrorHandler->renderException(Object(yii\\web\\NotFoundHttpException))\n#2 /home/www/cmc_console/vendor/sentry/Raven/ErrorHandler.php(86): yii\\base\\ErrorHandler->handleException(Object(yii\\web\\NotFoundHttpException))\n#3 [internal function]: Raven_ErrorHandler->handleException(Object(yii\\web\\NotFoundHttpException))\n#4 {main}\nPrevious exception:\nyii\\base\\InvalidRouteException: Unable to resolve the request: nav-bar/service-side-bar-1 in /home/www/cmc_console/vendor/yiisoft/yii2/base/Controller.php:143\nStack trace:\n#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Module.php(528): yii\\base\\Controller->runAction('service-side-ba...', Array)\n#1 /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php(103): yii\\base\\Module->runAction('nav-bar/service...', Array)\n#2 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))\n#3 /home/www/cmc_console/web/index.php(13): yii\\base\\Application->run()\n#4 {main}\n\nNext yii\\web\\NotFoundHttpException: 页面未找到。 in /home/www/cmc_console/vendor/yiisoft/yii2/web/Application.php:115\nStack trace:\n#0 /home/www/cmc_console/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))\n#1 /home/www/cmc_console/web/index.php(13): yii\\base\\Application->run()\n#2 {main}",
    "code": 201001,
    "status": 500,
    "type": "yii\\web\\ServerErrorHttpException"
}

17、此时,前 3 个问题皆已经得到解决,仅剩下第 4 个问题,编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,参考 yii\base\Model::validate(),当响应状态码等于20x,但返回码不等于约定的成功返回码时,即业务逻辑失败,在将错误保存在 yii\base\Model::$errors 属性中后,不直接返回 false,而是返回 !$this->hasErrors()。在这种情况下,为何不也抛出异常,目的在于让调用方可以更为灵活地处理此种情况,是否抛出异常由调用方决定,而不是模型方法本身。

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        // 检查响应状态码是否等于20x
        $responseCode = isset($response->data['code']) ? $response->data['code'] : 0; // 返回码
        $responseMessage = isset($response->data[0]) ? $response->data[0] : ''; // 说明
        if ($response->isOk) {
            // 检查业务逻辑是否成功
            if ($responseCode === 10000) {
                return ['message' => $response->data['message'], 'data' => $response->data['data']['menu_data']];
            } elseif ($responseCode === 99998) {
                // 登录超时
                throw new HttpException(302, Yii::t('error', Yii::t('error', Yii::t('error', '201002'), ['code' => $responseCode, 'message' => $response->data['message']])), 201003);
            } else {
                $this->addError('id', Yii::t('error', Yii::t('error', Yii::t('error', '201002'), ['code' => $responseCode, 'message' => $response->data['message']])));
                return !$this->hasErrors();
            }
        } else {
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201001'), ['status_code' => $response->statusCode, 'code' => $responseCode, 'message' => $responseMessage])), 201001);
        }

18、语言文件有所调整
common/messages/zh-CN/error.php

    201001 => '框架服务控制台HTTP请求失败,状态码:{status_code},返回码:{code},说明:{message}',
    201002 => '框架服务控制台HTTP请求失败,返回码:{code},说明:{message}',
    201003 => '',
    201010 => '{first_error}',

api/messages/zh-CN/error.php

    226020 => '{first_error}',

19、编辑方法文件:api/rests/menu/IndexAction.php,调用 HTTP 模型的方法:getMenu,由于 HTTP 模型文件 不直接返回 false,而是返回 !$this->hasErrors(),那么当返回 false 时,$model->hasErrors() 肯定等于 true,因此,可以省略其判断,代码如下

            // 所有输入数据都有效,获取模块的菜单信息
            $menu = $model->getMenu($model->login_id, $model->login_tid);

            if (!$menu) {
                $firstError = '';
                foreach ($model->getFirstErrors() as $message) {
                    $firstError = $message;
                    break;
                }
                throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '226020'), ['first_error' => $firstError])), 226020);
            }

20、当响应状态码等于20x,但返回码不等于约定的成功返回码时,即业务逻辑失败,获取菜单列表,符合预期,最后一个问题得到解决,如图6

图6

{
    "name": "Internal Server Error",
    "message": "框架服务控制台HTTP请求失败,返回码:99999,说明:menu_id不能为空",
    "code": 226020,
    "status": 500,
    "type": "yii\\web\\ServerErrorHttpException"
}

21、由于模型目录:common/logics/http/cmc_console 中的所有模型文件,皆是基于同一 HTTP 客户端组件,因此,其响应的处理逻辑基本上是一致的。决定将响应的处理逻辑封装为一个公共的方法,以便于复用。编辑 common/logics/http/cmc_console/Model.php

    /*
     * 响应对象的处理
     *
     * @param object $response 响应对象
     *
     * @return array|bool
     *
     * 格式如下:
     *
     * 框架服务控制台的菜单信息
     * [
     *     'message' => '', //说明
     *     'data' => [], //数据
     * ]
     *
     * 失败(将错误保存在 [[yii\base\Model::errors]] 属性中)
     * false
     *
     * @throws ServerErrorHttpException 如果响应状态码不等于20x
     * @throws HttpException 如果登录超时
     */    public function responseHandler($response)
    {
        // 检查响应状态码是否等于20x
        $responseCode = isset($response->data['code']) ? $response->data['code'] : 0; // 返回码
        if ($response->isOk) {
            // 检查业务逻辑是否成功
            if ($responseCode === 10000) {
                return ['message' => $response->data['message'], 'data' => $response->data['data']];
            } elseif ($responseCode === 99998) {
                // 登录超时
                throw new HttpException(302, Yii::t('error', Yii::t('error', Yii::t('error', '201002'), ['code' => $responseCode, 'message' => $response->data['message']])), 201003);
            } else {
                $this->addError('id', Yii::t('error', Yii::t('error', Yii::t('error', '201002'), ['code' => $responseCode, 'message' => $response->data['message']])));
                return !$this->hasErrors();
            }
        } else {
            $responseMessage = isset($response->data[0]) ? $response->data[0] : ''; // 说明
            throw new ServerErrorHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201001'), ['status_code' => $response->statusCode, 'code' => $responseCode, 'message' => $responseMessage])), 201001);
        }
    }

22、编辑 HTTP 模型文件:common/logics/http/cmc_console/Menu.php,在方法:getMenu 中,调用公共的响应对象的处理方法:responseHandler($response)

        $response = $this->httpClient->createRequest()
            ->setHeaders(['Cookie' => $cookie])
            ->setMethod('get')
            ->setUrl('nav-bar/service-side-bar')
            ->setData([
                'service_key' => $this->service_key,
            ])
            ->send();
        return $this->responseHandler($response);

 

 

永夜