新建了一个 webapp 对外提供接口服务, 这里没有选用rest/controller
, 因为现实项目中, 所有请求均使用了 POST 方式. 因此, 选用 web/controller
.
在 web.php 文件中进行了如下配置:
'errorHandler' => [
'errorAction' => 'site/error',
],
'response' => [
'format' => yii\web\Response::FORMAT_JSON,
'charset' => 'UTF-8',
'on afterSend' => function() {
\YII::error(['upstream_time' => \YII::getLogger()->getElapsedTime()], 'upstream_time');
\YII::error(\YII::getLogger()->getProfiling(['yii\db\Connection::open']), 'database_connection');
},
],
errorAction 主要逻辑如下:
class ErrorAction extends \yii\web\ErrorAction
{
public function run()
{
$enum = ExceptionEnum::_500_UNKNOWN_INTERNAL;
$template = array(
'error' => array(
'errno' => '500-' . $enum['cd'],
'errmsg' => $enum['msg'],
),
'data'=>array(),
);
\YII::$app->getResponse()->format = (Response::FORMAT_JSON);
$exception = $this->exception;
if($exception === null) {
return $template;
}
if ($exception instanceof \yii\web\HttpException) {
$code = $exception->statusCode . '-' . $exception->getCode();
}else {
$code = '500-' . $exception->getCode();
}
$template['error']['errno'] = $code;
if ($exception instanceof \Exception) {
$message = $exception->getMessage();
}else{
$message = \Yii::t('yii', $this->defaultMessage);
}
$message = strpos($message, 'SQLSTATE')!==false ? '数据库读写错误!' : $message;
$template['error']['errmsg'] = $message;
return $template;
}
}
配置完成后, 直接访问接口, 发现并未按照 errorAction->run()
处理结果. 追本溯源发现, 在web\ErrorHandler->renderException()
中:
$useErrorView = $response->format === Response::FORMAT_HTML && (!YII_DEBUG || $exception instanceof UserException);
if ($useErrorView && $this->errorAction !== null) {
$result = Yii::$app->runAction($this->errorAction);
if ($result instanceof Response) {
$response = $result;
} else {
$response->data = $result;
}
}
只有在$response->format === Response::FORMAT_HTML
情况下, 才会由配置中的 errorAction 进行处理.
修改办法
使用 web/controller, ErrorAction 中修改代码:
\YII::$app->getResponse()->format = (Response::FORMAT_JSON);
这样, 默认的响应格式是 html, 进入 ErrorAction 后再修改格式, 这样最终输出的是 json 格式.