必须使用 yii estController 或其子类,配置 UrlRule 启用严格解析,设置 JsonParser 解析器,并统一响应格式为 JSON,四者缺一不可;否则将出现空响应、text/html 头、406 错误或 POST body 解析失败。

要让 Yii3.0 的 API 接口稳定返回 JSON 数据,不能依赖自动协商或全局行为——必须明确控制器类型、响应格式、序列化器和请求解析器四者协同生效;漏掉任一环节,就会出现空响应、text/html 头、406 错误或 POST body 解析失败。
控制器必须继承 yii estController 或其子类
普通 yiiaseController 会触发视图渲染,导致 JSON 响应混入 HTML 模板或直接崩溃。【必须用 rest 控制器】
创建控制器时,使用命令行生成并手动修改基类:
php yii g/controller User --base-class=\yii\rest\Controller
打开生成的 controllers/UserController.php,确认 class 声明为:
class UserController extends yii
estController
若需自动 CRUD(如 GET /users、POST /users),改用 yii estActiveController,并声明 public $modelClass = 'appmodelsUser'; ——否则 index/view 等动作不会注册。
配置 URL 路由规则启用 REST 自动映射
Yii3 不再默认启用 REST 路由,必须显式注册 UrlRule 并开启严格解析。
在 config/web.php 的 components['urlManager']['rules'] 中添加:
'class' => yii
estUrlRule::class,
'controller' => ['v1/user'],
'pluralize' => true
同时确保 urlManager 启用关键开关:
enablePrettyUrl => true,
enableStrictParsing => true,
showScriptName => false
【enableStrictParsing 必须为 true】,否则未匹配路径将 fallback 到 site/index,返回 HTML 而非 404 JSON 错误。
设置请求体解析器支持 JSON 输入
前端发来的 {"name":"test"} 放在 request body 里,默认无法通过 $request->post() 获取——因为 Yii3 不自动解析 application/json 类型的原始 body。
第一步:在 config/web.php 的 components['request'] 中添加 parsers 配置:
'parsers' => [
'application/json' => yiiwebJsonParser::class,
],
基于三引擎设计,从微信文章、新闻和博客网页提取干净内容,支持标题作者日期元数据,多格式和批量处理。
第二步:确保控制器动作中使用 $request->getBodyParams() 而非 $_POST 或 $request->post() —— 后两者只处理表单编码数据。
第三步:若使用 ActiveController,它内部已调用 getBodyParams(),无需额外改动;但自定义 action 中必须显式调用。
强制统一 JSON 响应格式(含错误)
Yii3 默认仅对 Accept: application/json 请求返回 JSON,而 Postman/curl 默认不带该头,导致 500 错误仍返回 HTML。
方法一:在入口文件 web/index.php 中,于 Application 实例 run() 前插入:
Yii::$app->on(yiiaseApplication::EVENT_BEFORE_REQUEST, function ($event) {
if (str_contains(Yii::$app->request->getContentType(), 'application/json') || Yii::$app->request->isAjax) {
Yii::$app->response->format = yiiwebResponse::FORMAT_JSON;
}
});
方法二(推荐):为 API 模块单独配置 errorHandler 组件,在模块 config 中写:
'errorHandler' => [
'errorAction' => 'v1/error',
],
然后在 controllers/v1/ErrorController.php 中,actionError() 直接 return ['code' => $exception->getCode(), 'message' => $exception->getMessage()] —— 此时 response format 已由 beforeRequest 设定,无需重复设 format。
注意:不要在 actionError 里调用 $this->render() 或 echo,这会破坏 JSON 流程。
验证响应头与内容是否正确
用 curl 测试,必须带 -H "Accept: application/json" 和 -H "Content-Type: application/json":
curl -X GET http://localhost/users -H "Accept: application/json"
查看响应头是否含 Content-Type: application/json;若返回 HTML,说明 UrlRule 未生效或控制器基类错误。
用浏览器直接访问 /users 会返回 406 —— 这是正常行为,证明 content negotiation 已启用;若返回 HTML 页面,则说明 enableStrictParsing = false 或路由未命中。
检查 runtime/logs/app.log,搜索 "Invalid JsonParser" 或 "No matching route" 可快速定位解析或路由问题。

















