没有不值得去解决的问题,也没有不值得去学习的技术!

Best Practices for Response Handling in the Yii 2 HTTP Client Extension

When the response status code is 20x but the return code is not the agreed-upon success return code, meaning the business logic has failed, getting the menu list behaves as expected. The last problem is resolved

1. Get the menu list, as shown in Figure 1.

Get the menu list
Figure 1
JSON

{
    "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. View the Available Debug Data, which originates from HTTP, as shown in Figure 2.

View Available Debug Data, which originates from HTTP
Figure 2
Plaintext

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

3. View the HTTP model file: common/logics/http/cmc_console/Menu.php. The code is as follows:

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 is a component that configures the HTTP client via application components. Reference URL: https://www.yiiframework.com/extension/yiisoft/yii2-httpclient/doc/guide/2.0/zh-cn/usage-setup-client-instance . View the configuration file: common/config/main-local.php

PHP

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

5. View the parameters file: common/config/params-local.php. Configuration parameters related to the HTTP client exist here.

PHP

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

6. View the method file: api/rests/menu/IndexAction.php. It calls the HTTP model’s method: getMenu. The code is as follows:

PHP

            // 所有输入数据都有效,获取模块的菜单信息
            $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. The current implementation has 4 problems, as shown in Figure 3.
(1) When the application needs to call multiple services via HTTP, the number of application components will keep increasing. Be careful not to register too many application components; they act like global variables, and using too many can make testing and maintenance more difficult. Generally, you can create local components on demand.
(2) When adding a new HTTP component, you need to update both configuration files simultaneously: common/config/main-local.php and common/config/params-local.php. This is repetitive and somewhat redundant.
(3) When the response status code is not 20x, the call is considered failed (in most cases, this business logic holds true). A server error exception is thrown, but the error exception information is not detailed enough. Once the call fails, it is difficult to troubleshoot the specific cause of the error.
(4) When calling the HTTP model’s method, the processing logic for the return value is too complex and somewhat redundant, and needs to be simplified.

The current implementation has 4 problems
Figure 3

8. First, solve problem 1. Reference URL: https://www.yiiframework.com/extension/yiisoft/yii2-httpclient/doc/guide/2.0/zh-cn/usage-setup-client-instance . Encapsulate the yii\httpclient\Client instance as a local component.

9. View the inheritance relationship: yii\httpclient\Client » yii\base\Component, common\logics\http\cmc_console\Menu » common\logics\http\cmc_console\Model » \yii\base\Model » yii\base\Component. Therefore, in the model: common\logics\http\cmc_console\Model, the yii\httpclient\Client instance can be encapsulated as a local component. Edit common/logics/http/cmc_console/Model.php to create the HTTP client object.

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\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. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. Replace Yii::$app->cmcConsoleHttp with $this->httpClient.

PHP

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

11. Edit the configuration file: common/config/main-local.php. Delete the component: cmcConsoleHttp.

12. Get the menu list, which can still be fetched normally. View the Available Debug Data, which originates from HTTP. The request remains unchanged, as shown in Figure 4.

Get the menu list, which can still be fetched normally. View Available Debug Data, which originates from HTTP. The request remains unchanged
Figure 4

13. At this point, the first 2 problems have been resolved. Next, solve problem 3. When calling the HTTP model’s method, the processing logic for the return value is too complex and somewhat redundant, and needs to be simplified. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. When the response status code is 500, meaning it is not 20x, the call is considered failed (in most cases, this business logic holds true). Print the response object.

PHP

        $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;

Plaintext
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] => 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}
    [_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. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. When the response status code is 500, meaning it is not 20x, the call is considered failed (in most cases, this business logic holds true). Print the response data.

PHP

        $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;

Plaintext
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. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. When the response status code is 500, meaning it is not 20x, the call is considered failed (in most cases, this business logic holds true). A server error exception is thrown, but the error exception information is not detailed enough. Once the call fails, it is difficult to troubleshoot the specific cause of the error.

PHP

        $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);
        }

JSON

{
    "name": "Internal Server Error",
    "message": "框架服务控制台HTTP请求失败,状态码:500",
    "code": 201001,
    "status": 500,
    "type": "yii\\web\\ServerErrorHttpException"
}

16. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. When the response status code is 500, meaning it is not 20x, the call is considered failed (in most cases, this business logic holds true). Throw a server error exception and improve the error exception information. Once a call fails, it is easier to troubleshoot the specific cause of the error, as shown in Figure 5.

Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. When the response status code is 500, meaning it is not 20x, the call is considered failed (in most cases, this business logic holds true). Throw a server error exception and improve the error exception information. Once a call fails, it is easier to troubleshoot the specific cause of the error
Figure 5
PHP

        $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);
        }

JSON

{
    "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. At this point, the first 3 problems have been resolved, leaving only problem 4. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. Referencing yii\base\Model::validate(), when the response status code is 20x but the return code is not the agreed-upon success return code, meaning the business logic has failed, after saving the errors in the yii\base\Model::$errors property, instead of directly returning false, return !$this->hasErrors(). In this case, why not also throw an exception? The purpose is to allow the caller to handle this situation more flexibly; whether to throw an exception is decided by the caller, not by the model method itself.

PHP

        $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. The language files have been adjusted:
common/messages/zh-CN/error.php

PHP

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

api/messages/zh-CN/error.php

PHP

    226020 => '{first_error}',

19. Edit the method file: api/rests/menu/IndexAction.php. It calls the HTTP model’s method: getMenu. Since the HTTP model file does not directly return false, but instead returns !$this->hasErrors(), when it returns false, $model->hasErrors() must be true. Therefore, this check can be omitted. The code is as follows:

PHP

            // 所有输入数据都有效,获取模块的菜单信息
            $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. When the response status code is 20x but the return code is not the agreed-upon success return code, meaning the business logic has failed, getting the menu list behaves as expected. The last problem is resolved, as shown in Figure 6.

When the response status code is 20x but the return code is not the agreed-upon success return code, meaning the business logic has failed, getting the menu list behaves as expected. The last problem is resolved
Figure 6
JSON

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

21. Since all model files in the model directory: common/logics/http/cmc_console are based on the same HTTP client component, their response processing logic is essentially identical. I decided to encapsulate the response processing logic into a common method for reuse. Edit common/logics/http/cmc_console/Model.php.

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. Edit the HTTP model file: common/logics/http/cmc_console/Menu.php. In the method: getMenu, call the common response object processing method: responseHandler($response).

PHP

        $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);

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系