¿Cómo generar contenido de cuerpo HTTP personalizado con CakePHP 3.4? El eco provoca el error "No se pueden emitir encabezados"
httpresponse cakephp-3.x (2)
Usando CakePHP 3.4, PHP 7.0.
Estoy intentando hacer un método de controlador realmente simple para generar algunos JSON. Está generando "No se pueden modificar los encabezados ...".
public function test() {
$this->autoRender = false;
echo json_encode([''method'' => __METHOD__, ''class'' => get_called_class()]);
}
Salida del navegador
{"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 ...)
Entiendo completamente por qué PHP se queja de esto. La pregunta es ¿por qué se queja CakePHP y qué puedo hacer al respecto?
Cabe señalar que CakePHP 2.x permitió esto.
¡Los controladores nunca deben hacer eco de los datos! Hacer eco de los datos puede provocar todo tipo de problemas, desde los datos que no se reconocen en el entorno de prueba, hasta que los encabezados no se pueden enviar e incluso se cortan los datos.
Hacerlo de esa manera ya estaba mal en CakePHP 2.x, aunque podría haber funcionado en algunas, tal vez incluso en la mayoría de las situaciones. Con la introducción de la nueva pila HTTP, CakePHP ahora verifica explícitamente los encabezados enviados antes de hacer eco de la respuesta y activará un error en consecuencia.
La forma correcta de enviar una salida personalizada era configurar y devolver el objeto de respuesta, o usar vistas serializadas, y sigue siendo el mismo en 3.x.
Cita de los documentos:
Las acciones de controlador generalmente usan
Controller::set()
para crear un contexto que View usa para representar la capa de vista. Debido a las convenciones que utiliza CakePHP, no necesita crear y renderizar la vista manualmente. En cambio, una vez que se haya completado una acción del controlador, CakePHP se encargará de representar y entregar la Vista.Si por alguna razón desea omitir el comportamiento predeterminado, puede devolver un objeto
Cake/Network/Response
de la acción con la respuesta totalmente creada.
* A partir de 3.4 sería
/Cake/Http/Response
Libro de cocina> Controladores> Acciones del controlador
Configurar la respuesta
Uso de la interfaz compatible con 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;
La interfaz compatible con PSR-7 utiliza métodos inmutables, de ahí la utilización del valor de retorno de
withStringBody()
y
withType()
.
En CakePHP <3.4.3,
withStringBody()
no está disponible, y en su lugar puede escribir directamente en la secuencia del cuerpo, lo que no cambiará el estado del objeto de respuesta:
$this->response->getBody()->write($content);
Usando la interfaz obsoleta
$content = json_encode([''method'' => __METHOD__, ''class'' => get_called_class()]);
$this->response->body($content);
$this->response->type(''json'');
// ...
return $this->response;
Use una vista serializada
$content = [''method'' => __METHOD__, ''class'' => get_called_class()];
$this->set(''content'', $content);
$this->set(''_serialize'', ''content'');
Esto requiere también usar el componente del controlador de solicitudes, y habilitar la ampliación del análisis y el uso de URL de
.json
con
.json
agregado, o enviar una solicitud adecuada con un encabezado de
application/json
accept.
Ver también
CakePHP 3 tiene algo llamado vistas JSON que le permiten devolver datos JSON. No he hecho ningún CakePHP antes, así que no sé el ciclo de vida de una solicitud, pero vale la pena investigarlo.