Когда приложение завершает обработку запроса, оно генерирует объект ответа и отправляет его конечному пользователю. Объект ответа содержит такую информацию, как код состояния HTTP, заголовки HTTP и тело. Конечной целью разработки веб-приложений является построение таких объектов ответа по различным запросам.
В большинстве случаев вы должны в основном иметь дело с компонентом приложения response, который является экземпляром yii\web\Response
, по умолчанию. Однако Yii также позволяет создавать собственные объекты ответа и отправлять их конечным пользователям, как мы объясним ниже.
Код статуса
Одна из первых вещей, которые вы сделали бы при построении ответа, - это указать, был ли запрос успешно обработан. Это можно сделать, установив свойство yii\web\Response::$statusCode
, которое может принимать один из допустимых кодов состояния HTTP. Например, чтобы указать, что запрос успешно обработан, вы можете установить код статуса 200, например:
Yii::$app->response->statusCode = 200;
Однако в большинстве случаев вам не нужно явно указывать код состояния. Это связано с тем, что значение yii\web\Response::$statusCode
по умолчанию равно 200. И если вы хотите указать, что запрос не увенчался успехом, вы можете выдать соответствующее исключение HTTP, например:
throw new \yii\web\NotFoundHttpException;
Когда обработчик ошибок перехватывает исключение, он извлекает код состояния из исключения и присваивает его ответу. Для yii\web\NotFoundHttpException выше, оно связано с HTTP-статусом 404. Следующие исключения HTTP предопределены в Yii:
yii\web\BadRequestHttpException
: status code 400.yii\web\ConflictHttpException
: status code 409.yii\web\ForbiddenHttpException
: status code 403.yii\web\GoneHttpException
: status code 410.yii\web\MethodNotAllowedHttpException
: status code 405.yii\web\NotAcceptableHttpException
: status code 406.yii\web\NotFoundHttpException
: status code 404.yii\web\ServerErrorHttpException
: status code 500.yii\web\TooManyRequestsHttpException
: status code 429.yii\web\UnauthorizedHttpException
: status code 401.yii\web\UnsupportedMediaTypeHttpException
: status code 415.
Если исключение, которое вы хотите выбросить, не входит в список выше, вы можете создать его, расширив его с yii\web\HttpException
или напрямую передав его с кодом состояния, например:
throw new \yii\web\HttpException(402);
Заголовки HTTP
Вы можете отправлять HTTP-заголовки, манипулируя коллекцией заголовков в компоненте response. Например:
$headers = Yii::$app->response->headers;
// добавьте заголовок Pragma. Существующие заголовки Pragma НЕ будут перезаписаны.
$headers->add('Pragma', 'no-cache');
// установите заголовок Pragma. Любые существующие заголовки Pragma будут отброшены.
$headers->set('Pragma', 'no-cache');
// удалить заголовки Pragma и вернуть удаленные значения заголовка Pragma в массиве
$values = $headers->remove('Pragma');
Тело ответа
В большинстве ответов должен быть текст, который будет показывать контент, который вы хотите показывать конечным пользователям. Если у вас уже есть отформатированная строка тела, вы можете назначить ее свойству yii\web\Response::$content
ответа. Например:
Yii::$app->response->content = 'hello world!';
Если ваши данные нужно отформатировать перед отправкой их конечным пользователям, вы должны установить оба формата и свойства данных. Свойство format указывает, в каком формате данные должны быть отформатированы. Например:
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON;
$response->data = ['message' => 'hello world'];
Yii поддерживает следующие форматы, каждый из которых реализован классом форматирования. Вы можете настроить эти форматировщики или добавить новые, настроив свойство yii\web\Response::$formatters
.
- HTML: осуществляется
yii\web\HtmlResponseFormatter
. - XML: осуществляется
yii\web\XmlResponseFormatter
. - JSON: осуществляется
yii\web\JsonResponseFormatter
. - JSONP: осуществляется
yii\web\JsonResponseFormatter
. - RAW: используйте этот формат, если вы хотите отправить ответ без применения форматирования.
Хотя тело ответа можно задать явно, как показано выше, в большинстве случаев вы можете установить его неявно с помощью возвращаемого значения методов действия. Общий случай использования выглядит следующим образом:
public function actionIndex()
{
return $this->render('index');
}
Указанное выше действие index возвращает результат рендеринга представления index. Возвращаемое значение будет принято компонентом response, отформатировано, а затем отправлено конечным пользователям.
Поскольку по умолчанию формат ответа - HTML, вы должны только возвращать строку в методе действия. Если вы хотите использовать другой формат ответа, вы должны установить его перед возвратом данных. Например:
public function actionInfo()
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'message' => 'hello world',
'code' => 100,
];
}
Как уже упоминалось, помимо использования компонента приложения response по умолчанию, вы также можете создавать свои собственные объекты ответа и отправлять их конечным пользователям. Вы можете сделать это, вернув такой объект в метод действия, например:
public function actionInfo()
{
return \Yii::createObject([
'class' => 'yii\web\Response',
'format' => \yii\web\Response::FORMAT_JSON,
'data' => [
'message' => 'hello world',
'code' => 100,
],
]);
}
Перенаправление браузера
Перенаправление браузера зависит от отправки HTTP-заголовка Location. Поскольку эта функция обычно используется, Yii обеспечивает некоторую особую поддержку для нее.
Вы можете перенаправить браузер пользователя на URL-адрес, вызвав метод yii\web\Response::redirect()
. Метод устанавливает соответствующий заголовок Location с заданным URL-адресом и возвращает сам объект ответа. В методе действия вы можете вызвать его ярлык yii\web\Controller::redirect()
. Например:
public function actionOld()
{
return $this->redirect('http://example.com/new', 301);
}
В приведенном выше коде метод действия возвращает результат метода redirect()
. Как объяснялось выше, объект ответа, возвращаемый методом действия, будет использоваться как отсылка ответа конечным пользователям.
В местах, отличных от метода действия, вам следует сразу вызвать yii\web\Response::redirect()
, после чего следует связанный вызов метода yii\web\Response::send()
, чтобы гарантировать, что дополнительный контент не будет добавлен к ответ.
\Yii::$app->response->redirect('http://example.com/new', 301)->send();
Если текущий запрос является запросом AJAX, отправка заголовка местоположения не приведет автоматически к перенаправлению браузера. Чтобы решить эту проблему, метод yii\web\Response::redirect()
задает заголовок X-Redirect с URL-адресом переадресации в качестве его значения. На стороне клиента вы можете написать код JavaScript, чтобы прочитать это значение заголовка и соответственно перенаправить браузер.
Отправка файлов
Подобно переадресации браузера, отправка файлов - еще одна функция, которая использует определенные HTTP-заголовки. Yii предоставляет набор методов для поддержки различных потребностей отправки файлов. Все они имеют встроенную поддержку заголовка диапазона HTTP.
yii\web\Response::sendFile()
: отправляет существующий файл клиенту.yii\web\Response::sendContentAsFile()
: отправляет текстовую строку в виде файла клиенту.yii\web\Response::sendStreamAsFile()
: отправляет существующий поток файлов в виде файла клиенту.
Эти методы имеют одинаковую подпись метода с объектом ответа в качестве возвращаемого значения. Если файл, который нужно отправить, очень большой, вы должны рассмотреть возможность использования yii\web\Response::sendStreamAsFile()
, потому что он более эффективен в отношении памяти. В следующем примере показано, как отправить файл в действие контроллера:
public function actionDownload()
{
return \Yii::$app->response->sendFile('path/to/file.txt');
}
Если вы вызываете метод отправки файла в других местах, кроме метода действия, вам также следует вызвать метод yii\web\Response::send()
, чтобы гарантировать, что дополнительный текст не будет добавлен в ответ.
\Yii::$app->response->sendFile('path/to/file.txt')->send();
На некоторых веб-серверах имеется специальная поддержка отправки файлов, называемая X-Sendfile
. Идея заключается в перенаправлении запроса на файл на веб-сервер, который будет непосредственно служить файлу. В результате веб-приложение может завершиться раньше, пока веб-сервер отправляет файл. Чтобы использовать эту функцию, вы можете вызвать yii\web\Response::xSendFile()
. В следующем списке показано, как включить функцию X-Sendfile
для некоторых популярных веб-серверов:
- Apache: X-Sendfile
- Lighttpd v1.4: X-LIGHTTPD-send-file
- Lighttpd v1.5: X-Sendfile
- Nginx: X-Accel-Redirect
- Cherokee: X-Sendfile and X-Accel-Redirect
Отправка ответа
Содержимое в ответе не отправляется пользователю до тех пор, пока не будет вызван метод yii\web\Response::send()
. По умолчанию этот метод будет вызываться автоматически в конце yii\base\Application::run()
. Однако вы можете явно вызвать этот метод, чтобы немедленно отправить ответ.
Метод yii\web\Response::send() выполняет следующие шаги для отправки ответа:
- Запустите событие
yii\web\Response::EVENT_BEFORE_SEND
. - Вызовите
yii\web\Response::prepare()
, чтобы отформатировать ответные данные в ответном контенте. - Запустите событие
yii\web\Response::EVENT_AFTER_PREPARE
. - Вызовите
yii\web\Response::sendHeaders()
, чтобы отправить зарегистрированные HTTP-заголовки. - Вызовите
yii\web\Response::sendContent()
, чтобы отправить содержимое тела ответа. - Запустите событие
yii\web\Response::EVENT_AFTER_SEND
.
После того, как yii\web\Response::send()
вызывается один раз, дальнейший вызов этого метода будет проигнорирован. Это означает, что как только ответ будет отправлен, вы не сможете добавить к нему больше контента.
Как вы можете видеть, метод yii\web\Response::send()
запускает несколько полезных событий. Отвечая на эти события, можно настроить или украсить ответ.
0 комментариев