問題描述
使用 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 消息接口
這篇關于如何使用 CakePHP 3.4 輸出自定義 HTTP 正文內容?回聲導致“無法發出標頭"錯誤的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!