6

使用 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 允许这样做。

4

2 回答 2

13

控制器不应该回显数据!回显数据会导致各种问题,从测试环境中无法识别数据,到无法发送标头,甚至数据被截断。

这样做在 CakePHP 2.x 中已经是错误的,尽管它可能在某些甚至大多数情况下都有效。随着新 HTTP 堆栈的引入,CakePHP 现在在回显响应之前显式检查发送的标头,并相应地触发错误。

发送自定义输出的正确方法是配置并返回响应对象,或者使用序列化视图,在 3.x 中仍然相同。

从文档中引用:

控制器操作通常用于Controller::set()创建 View 用来呈现视图层的上下文。由于 CakePHP 使用的约定,您不需要手动创建和呈现视图。相反,一旦控制器动作完成,CakePHP 将处理呈现和交付视图。

如果出于某种原因您想跳过默认行为,您可以Cake\Network\Response从操作中返回一个带有完全创建响应的对象。

* 从 3.4 开始,这将是\Cake\Http\Response

食谱 > 控制器 > 控制器动作

配置响应

使用 PSR-7 兼容接口

$content = json_encode(['method' => __METHOD__, 'class' => get_called_class()]);

$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
// ...

return $this->response;

withStringBody()PSR-7 兼容接口使用不可变方法,因此使用了and的返回值withType()。在 CakePHP < 3.4.3 中,withStringBody()不可用,您可以改为直接写入主体流,这不会改变响应对象的状态:

$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/json接受标头的正确请求。

也可以看看

于 2017-02-21T22:56:45.693 回答
0

CakePHP 3 有一个叫做JSON 视图的东西,它允许你返回 JSON 数据。我之前没有做过任何 CakePHP,所以我不知道请求的生命周期,但值得研究一下。

于 2017-02-21T22:06:58.287 回答