yii2 restful接口默认不支持xml,需手动注册xmlresponseformatter、在contentnegotiator中配置formats包含application/xml、确保返回数据为数组或实现toarray()方法,且启用acceptheader=true或formatparam='format'之一。

Yii2 的 RESTful 接口默认不返回 XML,必须显式配置 ContentNegotiator 行为并注册 Response::FORMAT_XML 格式,否则哪怕 URL 带 .xml 后缀或请求头带 Accept: application/xml,也会 fallback 到 JSON 或 HTML。
为什么加了 .xml 后缀还是返回 JSON?
URL 后缀本身不触发格式切换,它只是路由匹配的一部分。Yii 不会自动把 .xml 映射成 Accept: application/xml,除非你主动告诉框架这么做。
- 确保
urlManager配置中启用了'enablePrettyUrl' => true和'showScriptName' => false,否则 Web 服务器(如 Nginx)可能直接截断后缀,导致路由未命中 - 在
urlManager::rules中添加通配符规则,例如'api/<controller:>.<format:>' => 'api/<controller>/index'</controller></format:></controller:>,让.xml被捕获为format参数 -
ContentNegotiator默认不读取 URL 参数,需显式设'acceptParam' => 'format',否则它只看Accept请求头 - 如果同时设置了
formatParam => 'format'(比如用?format=xml),又开了acceptHeader => true,二者冲突时Accept头会被忽略——这是最常被踩的坑
怎么让 ContentNegotiator 正确支持 XML?
XML 支持不是开箱即用的,必须手动注册格式、确保数据可序列化,并处理常见报错。
- 在控制器的
behaviors()中声明ContentNegotiator,且formats数组必须包含'application/xml' => \yii\web\Response::FORMAT_XML -
Response::FORMAT_XML要求返回的数据是数组,或对象实现了toArray()方法;原生 PHP 对象(没继承BaseObject或没定义toArray())会抛出InvalidCallException - 别漏掉
response.formatters配置:在应用配置里确保'xml' => ['class' => 'yii\web\XmlResponseFormatter']已注册,否则即使协商成功,序列化阶段也会失败 - XML 格式不支持
null值直接输出,遇到null字段会转为空标签(如<field></field>),若业务要求严格结构,需提前过滤或替换
Accept 头和 URL 后缀谁优先?
默认没有优先级逻辑,ContentNegotiator 只按你配置的参数来源工作。要实现“URL 版本 > Accept 头 > 默认版本”这类真实业务流,得自己写解析逻辑。
- Yii 自身不提供多层优先级协商,
acceptParam和acceptHeader是互斥开关,不能同时生效 - 常见做法是在
beforeAction()里手动提取$this->request->get('format')或解析路由中的后缀,再调用$this->response->format = Response::FORMAT_XML强制覆盖 - 如果坚持用
ContentNegotiator,只能二选一:要么关掉acceptHeader,全靠format参数驱动;要么关掉acceptParam,全靠请求头驱动 - RESTful 场景下建议关闭
acceptParam,仅启用acceptHeader => true,因为标准 API 客户端更依赖Accept头而非后缀
XML 输出容易卡在数据结构上——不是配置没写对,而是返回值没满足 toArray() 协议;另外,ContentNegotiator 的 only 和 except 很容易配错范围,导致部分 action 意外走默认格式。这些点不跑一遍真实请求几乎发现不了。











