使用CakePHP 3.4,PHP 7.0。
我正在尝试做一个非常简单的控制器方法来输出一些JSON。它输出“无法修改标题…”。
public function test() { $this->autoRender = false; echo json_encode(['method' => __METHOD__, 'class' => get_called_class()]); }
浏览器输出
{"method":"App\\Controller\\SomeController::test", "class":"App\\Controller\\SomeController"} Warning (512): Unable to emit headers. Headers sent in file=... Warning (2): Cannot modify header information - headers already sent by (output started at ...) Warning (2): Cannot modify header information - headers already sent by (output started at ...)
我完全理解为什么PHP对此有所抱怨。问题是为什么CakePHP会抱怨,我该怎么办?
应该注意的是CakePHP 2.x允许这样做。
控制器永远不要回显数据!回传数据会导致各种问题,从测试环境中无法识别的数据到无法发送的报头,甚至数据都被切断。
在CakePHP 2.x中这样做是错误的,即使它在某些甚至大多数情况下都可行。通过引入新的HTTP堆栈,CakePHP现在在回显响应之前显式检查发送的标头,并相应地触发错误。
发送自定义输出的正确方法是配置并返回响应对象,或使用序列化视图,并且在3.x中仍然相同。
从文档引用:
控制器动作通常用于Controller::set()创建View用于渲染视图图层的上下文。由于CakePHP使用的约定,因此不需要手动创建和呈现视图。相反,一旦控制器动作完成,CakePHP将处理呈现和交付View。 如果出于某种原因您想跳过默认行为,则可以Cake\Network\Response从具有完整创建的响应的操作中返回一个对象。
控制器动作通常用于Controller::set()创建View用于渲染视图图层的上下文。由于CakePHP使用的约定,因此不需要手动创建和呈现视图。相反,一旦控制器动作完成,CakePHP将处理呈现和交付View。
Controller::set()
如果出于某种原因您想跳过默认行为,则可以Cake\Network\Response从具有完整创建的响应的操作中返回一个对象。
Cake\Network\Response
*从3.4开始\Cake\Http\Response
\Cake\Http\Response
食谱 >控制器>控制器动作
$content = json_encode(['method' => __METHOD__, 'class' => get_called_class()]); $this->response = $this->response->withStringBody($content); $this->response = $this->response->withType('json'); // ... return $this->response;
对PSR-7兼容的接口使用不可改变的方法,的返回值的因而利用率withStringBody()和withType()。在CakePHP <3.4.3中,withStringBody()它不可用,您可以直接写入主体流,而不会更改响应对象的状态:
withStringBody()
withType()
$this->response->getBody()->write($content);
$content = json_encode(['method' => __METHOD__, 'class' => get_called_class()]); $this->response->body($content); $this->response->type('json'); // ... return $this->response;
$content = ['method' => __METHOD__, 'class' => get_called_class()]; $this->set('content', $content); $this->set('_serialize', 'content');
这还需要使用请求处理程序组件,并允许扩展解析和使用带有.json追加的对应URL ,或发送带有application/jsonaccept标头的适当请求。
.json
application/json