Как вывести пользовательское содержимое тела HTTP с помощью CakePHP 3.4? Эховые причины Ошибка «Невозможно испустить заголовки»

Использование 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

Поваренная книга> Контроллеры> Действия контроллера

Настроить ответ

Использование интерфейса, совместимого с PSR-7

 $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.

Смотрите также

  • Поваренная книга> Контроллеры> Действия контроллера
  • Cookbook> Views> JSON и представления XML
  • Стандарты PHP FIG> Интерфейсы HTTP-сообщений PSR-7

CakePHP 3 имеет нечто вроде представлений JSON, которое позволяет вам возвращать данные JSON. Раньше я еще не делал CakePHP, поэтому я не знаю жизненного цикла запроса, но стоит посмотреть.