Использование 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 будет обрабатывать рендеринг и доставку представления.Если по какой-то причине вы хотите пропустить поведение по умолчанию, вы можете вернуть объект
Cake\Network\Response
из действия с полностью созданным ответом.
* Начиная с 3.4, это будет \Cake\Http\Response
Поваренная книга> Контроллеры> Действия контроллера
$content = json_encode(['method' => __METHOD__, 'class' => get_called_class()]); $this->response->getBody()->write($content); $this->response = $this->response->withType('json'); // ... return $this->response;
Интерфейс, совместимый с PSR-7, использует неизменные методы, поэтому используется возвращаемое значение withType()
. В отличие от настроек заголовков и прочее, изменение тела путем записи в существующий поток не изменяет состояние объекта ответа.
CakePHP 3.4.3 добавит неизменяемый метод withStringBody
который может использоваться альтернативно для записи в существующий поток.
$this->response = $this->response->withStringBody($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');
Для этого требуется также использовать компонент обработчика запроса и разрешить разбор парсинга и использовать соответствующие URL-адреса с помощью .json
или отправить соответствующий запрос с заголовком application/json
accept.
CakePHP 3 имеет нечто вроде представлений JSON, которое позволяет вам возвращать данные JSON. Раньше я еще не делал CakePHP, поэтому я не знаю жизненного цикла запроса, но стоит посмотреть.