Yii2 RESTful接口通过ContentNegotiator行为控制响应格式,依据Accept请求头与formats配置匹配;强制JSON需覆盖formats为['application/json'=>Response::FORMAT_JSON,'/'=>Response::FORMAT_JSON],并确保使用yii\rest\Controller及其子类。

Yii2 RESTful 接口如何控制响应格式(JSON/XML)
Yii2 的 RESTful 接口默认支持 JSON 和 XML 两种格式,但实际返回哪种,取决于客户端 Accept 请求头 + 服务端 ContentNegotiator 配置的共同作用。不显式干预时,它会按 q 权重匹配,但多数 API 场景下你只想返回 JSON —— 这时不能靠“客户端发什么就回什么”,而要强制协商结果。
修改 ContentNegotiator::formats 强制只输出 JSON
最直接有效的方式是在控制器的 behaviors() 中覆盖默认协商规则。注意:不是改 Response::format,而是改 contentNegotiator 行为里的 formats 映射表。
-
formats的 key 是 MIME 类型(如'application/json'),value 是 Yii 内置的格式常量(如Response::FORMAT_JSON) - 把不需要的格式(比如
'text/html'、'application/xml')映射到Response::FORMAT_JSON,等效于“全部转 JSON” - 如果只留
['application/json' => Response::FORMAT_JSON],客户端发Accept: application/xml会直接 406 Not Acceptable
示例(在 UserController.php 中):
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats'] = [
'application/json' => Response::FORMAT_JSON,
'text/html' => Response::FORMAT_JSON,
];
return $behaviors;
}
全局统一设为 JSON(适用于纯 API 项目)
如果你的整个应用就是后端 API(比如面向 App 或前端 SPA),没必要每个控制器都写一遍。直接在 config/web.php 的 as contentNegotiator 全局行为里配置,更干净。
- 必须放在
as数组中,且需确保它在所有控制器 action 执行前生效 - 不要漏掉
'*/*'这个兜底 MIME,否则某些没带Accept头的请求可能失败 - 全局设置后,
ActiveController自带的contentNegotiator会被覆盖,无需再在控制器里重复配置
配置片段(config/web.php):
'as contentNegotiator' => [
'class' => 'yii\filters\ContentNegotiator',
'formats' => [
'application/json' => Response::FORMAT_JSON,
'*/*' => Response::FORMAT_JSON,
],
],
为什么有时改了 formats 还返回 XML?
常见原因不是配置错,而是中间环节干扰了协商流程:
- 你在控制器里手动调用了
$this->response->format = Response::FORMAT_XML,这会直接覆盖协商结果 - 自定义的
Serializer或Response子类在prepare()里硬编码了Content-Type头 -
urlManager规则里启用了suffix(如'suffix' => '.xml'),Yii 会优先按后缀判断格式,绕过Accept头 - 你用的是
yii\web\Controller而非yii\rest\ActiveController,后者才默认注入contentNegotiator行为
最稳妥的验证方式:用 curl -H "Accept: application/xml" http://localhost/users 测试,看响应头 Content-Type 是什么 —— 别只看返回体是否像 JSON。


















