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/*" ] } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }
以上是现象。
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 \yii\base\Event $event
*/
public function beforeSend($event)
{
/* @var $response \yii\web\Response */
$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实例化,这种情况一般是不常见的。所以出现这种现象是特定情况。问题已找到。

浙公网安备 33010602011771号