0 follower

Respuestas

Cuando una aplicación finaliza la gestión de una petición (request), genera un objeto response y lo envía al usuario final. El objeto response contiene información tal como el código de estado (status code) HTTP, las cabeceras (headers) HTTP y el cuerpo (body). El objetivo final del desarrollo de una aplicación Web es esencialmente construir objetos response para varias peticiones.

En la mayoría de casos principalmente se debe tratar con componentes de aplicación de tipo response que, por defecto, son una instancia de yii\web\Response. Sin embargo, Yii permite crear sus propios objetos response y enviarlos al usuario final tal y como se explica a continuación.

En esta sección, se describirá como generar y enviar respuestas a usuarios finales.

Códigos de Estado

Una de las primeras cosas que debería hacerse cuando se genera una respuesta es indicar si la petición se ha gestionado correctamente. Esto se indica asignando la propiedad yii\web\Response::$statusCode a la que se le puede asignar cualquier valor válido dentro de los códigos de estado HTTP. Por ejemplo, para indicar que la petición se ha gestionado correctamente, se puede asignar el código de estado a 200, como en el siguiente ejemplo:

Yii::$app->response->statusCode = 200;

Sin embargo, en la mayoría de casos nos es necesario asignar explícitamente el código de estado. Esto se debe a que el valor por defecto de yii\web\Response::$statusCode es 200. Y si se quiere indicar que la petición ha fallado, se puede lanzar una excepción HTTP apropiada como en el siguiente ejemplo:

throw new \yii\web\NotFoundHttpException;

Cuando el error handler captura una excepción, obtendrá el código de estado de la excepción y lo asignará a la respuesta. En el caso anterior, la excepción yii\web\NotFoundHttpException está asociada al estado HTTP 404. En Yii existen las siguientes excepciones predefinidas.

Si la excepción que se quiere lanzar no se encuentra en la lista anterior, se puede crear una extendiendo yii\web\HttpException, o directamente lanzando un código de estado, por ejemplo:

throw new \yii\web\HttpException(402);

Cabeceras HTTP

Se puede enviar cabeceras HTTP modificando el header collection en el componente response. Por ejemplo:

$headers = Yii::$app->response->headers;

// añade una cabecera Pragma. Las cabeceras Pragma existentes NO se sobrescribirán.
$headers->add('Pragma', 'no-cache');

// asigna una cabecera Pragma. Cualquier cabecera Pragma existente será descartada.
$headers->set('Pragma', 'no-cache');

// Elimina las cabeceras Pragma y devuelve los valores de las eliminadas en un array
$values = $headers->remove('Pragma');

Información: Los nombres de las cabeceras case insensitive, es decir, no discriminan entre mayúsculas y minúsculas. Además, las nuevas cabeceras registradas no se enviarán al usuario hasta que se llame al método yii\web\Response::send().

Cuerpo de la Respuesta

La mayoría de las respuestas deben tener un cuerpo que contenga el contenido que se quiere mostrar a los usuarios finales.

Si ya se tiene un texto de cuerpo con formato, se puede asignar a la propiedad yii\web\Response::$content del response. Por ejemplo:

Yii::$app->response->content = 'hello world!';

Si se tiene que dar formato a los datos antes de enviarlo al usuario final, se deben asignar las propiedades format y data. La propiedad format especifica que formato debe tener data. Por ejemplo:

$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON;
$response->data = ['message' => 'hello world'];

Yii soporta a los siguientes formatos de forma predeterminada, cada uno de ellos implementado por una clase formatter. Se pueden personalizar los formatos o añadir nuevos sobrescribiendo la propiedad yii\web\Response::$formatters.

Mientras el cuerpo de la respuesta puede ser mostrado de forma explicita como se muestra a en el anterior ejemplo, en la mayoría de casos se puede asignar implícitamente por el valor de retorno de los métodos de acción. El siguiente, es un ejemplo de uso común:

public function actionIndex()
{
    return $this->render('index');
}

La acción index anterior, devuelve el resultado renderizado de la vista index. El valor devuelto será recogido por el componente response, se le aplicará formato y se enviará al usuario final.

Por defecto, el formato de respuesta es HTML, sólo se debe devolver un string en un método de acción. Si se quiere usar un formato de respuesta diferente, se debe asignar antes de devolver los datos. Por ejemplo:

public function actionInfo()
{
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    return [
        'message' => 'hello world',
        'code' => 100,
    ];
}

Como se ha mencionado, además de usar el componente de aplicación response predeterminado, también se pueden crear objetos response propios y enviarlos a los usuarios finales. Se puede hacer retornando un objeto en el método de acción, como en el siguiente ejemplo:

public function actionInfo()
{
    return \Yii::createObject([
        'class' => 'yii\web\Response',
        'format' => \yii\web\Response::FORMAT_JSON,
        'data' => [
            'message' => 'hello world',
            'code' => 100,
        ],
    ]);
}

Nota: Si se crea un objeto response propio, no se podrán aprovechar las configuraciones asignadas para el componente response en la configuración de la aplicación. Sin embargo, se puede usar la inyección de dependencias para aplicar la configuración común al nuevo objeto response.

Redirección del Navegador

La redirección del navegador se basa en el envío de la cabecera HTTP Location. Debido a que esta característica se usa comúnmente, Yii proporciona soporte especial para ello.

Se puede redirigir el navegador a una URL llamando al método yii\web\Response::redirect(). El método asigna la cabecera de Location apropiada con la URL proporcionada y devuelve el objeto response él mismo. En un método de acción, se puede acceder a él mediante el acceso directo yii\web\Controller::redirect() como en el siguiente ejemplo:

public function actionOld()
{
    return $this->redirect('https://example.com/new', 301);
}

En el ejemplo anterior, el método de acción devuelve el resultado del método redirect(). Como se ha explicado antes, el objeto response devuelto por el método de acción se usará como respuesta enviándola al usuario final.

En otros sitios que no sean los métodos de acción, se puede llamar a yii\web\Response::redirect() directamente seguido por una llamada al método yii\web\Response::send() para asegurar que no habrá contenido extra en la respuesta.

\Yii::$app->response->redirect('https://example.com/new', 301)->send();

Información: De forma predeterminada, el método yii\web\Response::redirect() asigna el estado de respuesta al código de estado 302 que indica al navegador que recurso solicitado está temporalmente alojado en una URI diferente. Se puede enviar un código de estado 301 para expresar que el recurso se ha movido de forma permanente.

Cuando la petición actual es de una petición AJAX, el hecho de enviar una cabecera Location no causará una redirección del navegador automática. Para resolver este problema, el método yii\web\Response::redirect() asigna una cabecera X-Redirect con el valor de la URL de redirección. En el lado del cliente se puede escribir código JavaScript para leer la esta cabecera y redireccionar el navegador como corresponda.

Información: Yii contiene el archivo JavaScript yii.js que proporciona un conjunto de utilidades comunes de JavaScript, incluyendo la redirección de navegador basada en la cabecera X-Redirect. Por tanto, si se usa este fichero JavaScript (registrándolo asset bundle yii\web\YiiAsset), no se necesitará escribir nada más para tener soporte en redirecciones AJAX.

Enviar Archivos

Igual que con la redirección, el envío de archivos es otra característica que se basa en cabeceras HTTP especificas. Yii proporciona un conjunto de métodos para dar soporte a varias necesidades del envío de ficheros. Todos ellos incorporan soporte para el rango de cabeceras HTTP.

Estos métodos tienen la misma firma de método con el objeto response como valor de retorno. Si el archivo que se envía es muy grande, se debe considerar usar yii\web\Response::sendStreamAsFile() porque es más efectivo en términos de memoria. El siguiente ejemplo muestra como enviar un archivo en una acción de controlador.

public function actionDownload()
{
    return \Yii::$app->response->sendFile('ruta/del/fichero.txt');
}

Si se llama al método de envío de ficheros fuera de un método de acción, también se debe llamar al método yii\web\Response::send() después para asegurar que no se añada contenido extra a la respuesta.

\Yii::$app->response->sendFile('ruta/del/fichero.txt')->send();

Algunos servidores Web tienen un soporte especial para enviar ficheros llamado X-Sendfile. La idea es redireccionar la petición para un fichero a un servidor Web que servirá el fichero directamente. Como resultado, la aplicación Web puede terminar antes mientras el servidor Web envía el fichero. Para usar esta funcionalidad, se puede llamar a yii\web\Response::xSendFile(). La siguiente lista resume como habilitar la característica X-Sendfile para algunos servidores Web populares.

Enviar la Respuesta

El contenido en una respuesta no se envía al usuario hasta que se llama al método yii\web\Response::send(). De forma predeterminada, se llama a este método automáticamente al final de yii\base\Application::run(). Sin embargo, se puede llamar explícitamente a este método forzando el envío de la respuesta inmediatamente.

El método yii\web\Response::send() sigue los siguientes pasos para enviar una respuesta:

  1. Lanza el evento yii\web\Response::EVENT_BEFORE_SEND.
  2. Llama a yii\web\Response::prepare() para convertir el response data en response content.
  3. Lanza el evento yii\web\Response::EVENT_AFTER_PREPARE.
  4. Llama a yii\web\Response::sendHeaders() para enviar las cabeceras HTTP registradas.
  5. Llama a yii\web\Response::sendContent() para enviar el contenido del cuerpo de la respuesta.
  6. Lanza el evento yii\web\Response::EVENT_AFTER_SEND.

Después de llamar a yii\web\Response::send() por primera vez, cualquier llamada a este método será ignorada. Esto significa que una vez se envíe una respuesta, no se le podrá añadir más contenido.

Como se puede observar, el método yii\web\Response::send() lanza varios eventos útiles. Al responder a estos eventos, es posible ajustar o decorar la respuesta.

Found a typo or you think this page needs improvement?
Edit it on github !