yii2 response多次输出问题的查找

{
    "IsSuccess": 1,
    "ErrMsg": "OK",
    "Data": {
        "IsSuccess": 1,
        "ErrMsg": "OK",
        "Data": {
            "IsSuccess": 1,
            "ErrMsg": "OK",
            "Data": {
                "IsSuccess": 1,
                "ErrMsg": "OK",
                "Data": {
                    "IsSuccess": 1,
                    "ErrMsg": "OK",
                    "Data": {
                        "error_code": 1,
                        "message": "OK",
                        "res_msg": {
                            "error_code": 1,
                            "message": "OK",
                            "res_msg": {
                                "error_code": 1,
                                "message": "OK",
                                "res_msg": {
                                    "error_code": 1,
                                    "message": "OK",
                                    "res_msg": {
                                        "error_code": 1,
                                        "message": "OK",
                                        "res_msg": {
                                            "error_code": 1,
                                            "message": "OK",
                                            "res_msg": {
                                                "error_code": 1,
                                                "message": "OK",
                                                "res_msg": {
                                                    "error_code": 1,
                                                    "message": "OK",
                                                    "res_msg": {
                                                        "error_code": 1,
                                                        "message": "OK",
                                                        "res_msg": {
                                                            "error_code": 1,
                                                            "message": "OK",
                                                            "res_msg": {
                                                                "error_code": 1,
                                                                "message": "OK",
                                                                "res_msg": {
                                                                    "error_code": 1,
                                                                    "message": "OK",
                                                                    "res_msg": {
                                                                        "error_code": 1,
                                                                        "message": "OK",
                                                                        "res_msg": {
                                                                            "error_code": 1,
                                                                            "message": "OK",
                                                                            "res_msg": {
                                                                                "error_code": 1,
                                                                                "message": "OK",
                                                                                "res_msg": {
                                                                                    "error_code": 1,
                                                                                    "message": "OK",
                                                                                    "res_msg": {
                                                                                        "error_code": 1,
                                                                                        "message": "OK",
                                                                                        "res_msg": {
                                                                                            "error_code": 1,
                                                                                            "message": "OK",
                                                                                            "res_msg": {
                                                                                                "error_code": 1,
                                                                                                "message": "OK",
                                                                                                "res_msg": {
                                                                                                    "error_code": 1,
                                                                                                    "message": "OK",
                                                                                                    "res_msg": {
                                                                                                        "error_code": 1,
                                                                                                        "message": "OK",
                                                                                                        "res_msg": {
                                                                                                            "error_code": 1,
                                                                                                            "message": "OK",
                                                                                                            "res_msg": {
                                                                                                                "error_code": 1,
                                                                                                                "message": "OK",
                                                                                                                "res_msg": {
                                                                                                                    "error_code": 1,
                                                                                                                    "message": "OK",
                                                                                                                    "res_msg": {
                                                                                                                        "error_code": 1,
                                                                                                                        "message": "OK",
                                                                                                                        "res_msg": {
                                                                                                                            "error_code": 1,
                                                                                                                            "message": "OK",
                                                                                                                            "res_msg": {
                                                                                                                                "error_code": 1,
                                                                                                                                "message": "OK",
                                                                                                                                "res_msg": {
                                                                                                                                    "error_code": 1,
                                                                                                                                    "message": "OK",
                                                                                                                                    "res_msg": {
                                                                                                                                        "error_code": 1,
                                                                                                                                        "message": "OK",
                                                                                                                                        "res_msg": {
                                                                                                                                            "available": [
                                                                                                                                                "/api/auth/view",
                                                                                                                                            ],
                                                                                                                                            "assigned": [
                                                                                                                                                "/*",
                                                                                                                                                "/admin/*",
                                                                                                                                                "/admin/api/*"
                                                                                                                                            ]
                                                                                                                                        }
                                                                                                                                    }
                                                                                                                                }
                                                                                                                            }
                                                                                                                        }
                                                                                                                    }
                                                                                                                }
                                                                                                            }
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
View Code

以上是现象。

action:

public function actionRefresh()
    {
        $model = new Route();
        $model->invalidate();
        return $model->getRoutes();
    }

访问这个action产生的。因为我这个controller继承了同事写的一个基controller,代码如下:

public function init()
    {
        parent::init();
        //绑定beforeSend事件,更改数据输出格式
        Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeSend']);
    }

    /**
     * 更改数据输出格式
     * 默认情况下输出Json数据
     * @param yiiaseEvent $event
     */
    public function beforeSend($event)
    {
        /* @var $response yiiwebResponse */
        $response = $event->sender;
        $msg = $response->statusText;
        $statusCode = $response->statusCode;
        $isSuccess = $response->getIsSuccessful();

        if(isset($response->data['code']) && $response->data['code']==0){
            $code = 0;
        }else{
            if($isSuccess){
                $code = 1;
            }else{
                $code = 0;
            }
        }
        if ($response->statusCode>=400) {
            //异常处理
            if (true && $exception = Yii::$app->getErrorHandler()->exception) {
                 $data = $response->data;
                //$data = $this->convertExceptionToArray($exception);
            }
            //Model出错了
            if ($response->statusCode==422) {
                $messages=[];
                foreach ($response->data as $v) {
                    $messages[] = $v['message'];
                }
                //请求错误时数据为  {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}}
                $data = [
                    'error_code' =>$code,
                    'message'=> implode("  ", $messages),
                    'res_msg'=>$response->data
                ];
            }
            $response->isSent = true;
          //  $response->statusCode = 200;
        }
        elseif ($response->statusCode>=300) {
          //  $response->statusCode = 200;
            $data = $this->convertExceptionToArray(new ForbiddenHttpException(Yii::t('yii', 'Login Required')));
        }
        else{
            $data = $response->data;
        }

        //请求正确时数据
        $response->data = [
            'error_code' =>$code,
            'message' => $msg,
            'res_msg' => empty($data) ? array('message'=>'暂无数据') : $data,
        ];

        $response->format = Response::FORMAT_JSON;
     //   Yii::$app->getResponse()->getHeaders()->set('Access-Control-Allow-Origin', '*');
      //  Yii::$app->getResponse()->getHeaders()->set('Access-Control-Allow-Credentials', 'true');

    }

在beforeSend中Yii::info($response->statusCode);

发现该事件Response::EVENT_BEFORE_SEND被多次触发,这就导致了上面那个现象。

在基础controller中没有检测该事件是否绑定handler,造成了多次多次重复绑定,因为在该次执行中对多个controller进行了实例化。

init中改为:

public function init()
    {
        parent::init();
        //绑定beforeSend事件,更改数据输出格式
        if (!Yii::$app->response->hasEventHandlers(Response::EVENT_BEFORE_SEND)) {
            // 避免重复绑定
            Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeSend']);
        }
    }

  方法

不过在加入了该判断后,发现少了一些输出,不过还有六次输出,如下:

{
    "IsSuccess": 1,
    "ErrMsg": "OK",
    "Data": {
        "IsSuccess": 1,
        "ErrMsg": "OK",
        "Data": {
            "IsSuccess": 1,
            "ErrMsg": "OK",
            "Data": {
                "IsSuccess": 1,
                "ErrMsg": "OK",
                "Data": {
                    "IsSuccess": 1,
                    "ErrMsg": "OK",
                    "Data": {
                        "error_code": 1,
                        "message": "OK",
                        "res_msg": {
                            "available": [
                                "/api/auth/view",
                                "/api/auth/create"
                            ],
                            "assigned": [
                                "/*",
                                "/admin/*",
                                "/admin/api/*",
                            ]
                        }
                    }
                }
            }
        }
    }
}

突然发现前面输出的是:

"IsSuccess": 1,
"ErrMsg": "OK",
"Data":{}

而这是我在另外一个基controller中绑定的事件发挥的结果格式,如下:

public function init() {
        parent::init();
        Event::on(
            Response::className(),
            Response::EVENT_BEFORE_SEND,
            [$this, 'formatDataBeforeSend']
        );
    }

很奇怪,他为啥跟这个混在一起了?

对了,这是因为出现这种情况是在获取系统所有route的方法getAppRoutes中,而其中有对所有controller进行实例化的动作。症结就在这里了。 

将init方法改造为:

public function init() {
        parent::init();
        if (!Event::hasHandlers(Response::className(), Response::EVENT_BEFORE_SEND)) {
            Event::on(
                Response::className(),
                Response::EVENT_BEFORE_SEND,
                [$this, 'formatDataBeforeSend']
            );
        }
    }

不过在这样处理后,还有问题,如下:

{
    "IsSuccess": 1,
    "ErrMsg": "OK",
    "Data": {
        "error_code": 1,
        "message": "OK",
        "res_msg": {
            "available": [
                "/api/auth/view",
                "/api/auth/create",
                "/api/auth/update",
            ],
            "assigned": [
                "/*",
                "/admin/*"
            ]
        }
    }
}

还有问题,不过这个问题的原因就在于这里因为对那个作为路由controller的中绑定事件的触发,加上正常的触发,导致了这个问题。

这个问题除了前面加上判断之外,还得处理一下,如下:

public function init() {
        parent::init();
        if (
            !Event::hasHandlers(Response::className(), Response::EVENT_BEFORE_SEND)
            && !Yii::$app->response->hasEventHandlers(Response::EVENT_BEFORE_SEND)
        ) {
            Event::on(
                Response::className(),
                Response::EVENT_BEFORE_SEND,
                [$this, 'formatDataBeforeSend']
            );
        }
    }

因为涉及到两种返回格式,且在一次访问中,多次触发controller实例化,这种情况一般是不常见的。所以出现这种现象是特定情况。问题已找到。

原文地址:https://www.cnblogs.com/jiangtian/p/10991576.html