如何使用 CakePHP 3.4 输出自定义 HTTP 正文内容?回声导致“无法发出标头"错误
使用 CakePHP 3.4、PHP 7.0.
Using CakePHP 3.4, PHP 7.0.
我正在尝试做一个非常简单的控制器方法来输出一些 JSON.它正在输出无法修改标题...".
I'm attempting to do a really simple controller method to output some JSON. It is outputting "Cannot modify headers...".
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 会抱怨,我该怎么办?
I fully understand why PHP complains about this. The question is why does CakePHP complain and what can I do about it?
需要注意的是,CakePHP 2.x 允许这样做.
It should be noted that CakePHP 2.x allowed this.
推荐答案
控制器不应该回显数据!回显数据会导致各种问题,从测试环境无法识别数据,到无法发送header,甚至数据被截断.
Controllers should never echo data! Echoing data can lead to all kinds of problems, from the data not being recognized in the test environment, to headers not being able to be sent, and even data being cut off.
那样做在 CakePHP 2.x 中已经是错误的了,尽管它可能在某些甚至大多数情况下都有效.随着新 HTTP 堆栈的引入,CakePHP 现在在回显响应之前显式检查发送的标头,并相应地触发错误.
Doing it that way was already wrong in CakePHP 2.x, even though it might have worked in some, maybe even most situations. With the introduction of the new HTTP stack, CakePHP now explicitly checks for sent headers before echoing the response, and will trigger an error accordingly.
发送自定义输出的正确方式是配置并返回响应对象,或者使用序列化视图,在 3.x 中仍然相同.
The proper way to send custom output was to configure and return the response object, or to use serialized views, and it's still the same in 3.x.
引自文档:
Controller 动作通常使用 Controller::set()
来创建一个上下文,View 用它来渲染视图层.由于 CakePHP 使用的约定,您不需要手动创建和呈现视图.相反,一旦控制器操作完成,CakePHP 将处理渲染和交付视图.
Controller actions generally use
Controller::set()
to create a context that View uses to render the view layer. Because of the conventions that CakePHP uses, you don’t need to create and render the view manually. Instead, once a controller action has completed, CakePHP will handle rendering and delivering the View.
如果出于某种原因您想跳过默认行为,您可以从具有完全创建响应的操作中返回一个 CakeNetworkResponse
对象.
If for some reason you’d like to skip the default behavior, you can return a CakeNetworkResponse
object from the action with the fully created response.
* 从 3.4 开始,这将是 CakeHttpResponse
食谱>控制器控制器操作
$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()
不可用,直接写入body流即可,不会改变响应对象的状态:
The PSR-7 compliant interface uses immutable methods, hence the utilization of the return value of withStringBody()
and withType()
. In CakePHP < 3.4.3, withStringBody()
is not available, and you can instead directly write to the body stream, which will not change the state of the response object:
$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
发送正确的请求代码> 接受标题.
This requires to also use the request handler component, and to enable extensing parsing and using correponsing URLs with .json
appended, or to send a proper request with a application/json
accept header.
- 食谱>控制器控制器操作
- 食谱>请求 &响应对象 >设置正文
- 食谱>视图 >JSON 和 XML 视图
- PHP FIG 标准 >PSR-7 HTTP 消息接口
相关文章