HTTP-ответ
Nette инкапсулирует HTTP-ответ в объекты с понятным API.
HTTP-ответ представлен объектом Nette\Http\Response. Если вы работаете с
Nette, этот объект создаёт фреймворк автоматически, и вы можете получить
его через внедрение
зависимостей. В презентерах достаточно вызвать метод
$this->getHttpResponse().
Nette\Http\Response
В отличие от Nette\Http\Request, этот объект
изменяемый, так что вы можете сеттерами менять состояние, например
отправлять заголовки. Помните, что все сеттеры нужно вызывать до
отправки какого-либо реального вывода. Метод isSent() говорит,
был ли вывод уже отправлен. Если он вернёт true, любая попытка
отправить заголовок выбросит Nette\InvalidStateException.
setCode (int $code, ?string $reason=null)
Меняет код состояния ответа. Для лучшей читаемости исходного кода вместо самих чисел рекомендуется использовать заранее определённые константы.
$httpResponse->setCode(Nette\Http\Response::S404_NotFound);
getCode(): int
Возвращает код состояния ответа.
isSent(): bool
Возвращает, были ли заголовки уже отправлены с сервера в браузер, то есть что отправлять заголовки или менять код состояния уже нельзя.
setHeader (string $name, ?string $value)
Отправляет HTTP-заголовок и перезаписывает ранее отправленный
заголовок с тем же именем. Если $value равно null, заголовок
будет удалён.
$httpResponse->setHeader('Pragma', 'no-cache');
addHeader (string $name, string $value)
Отправляет HTTP-заголовок и не перезаписывает ранее отправленный заголовок с тем же именем.
$httpResponse->addHeader('Accept', 'application/json');
$httpResponse->addHeader('Accept', 'application/xml');
deleteHeader (string $name)
Удаляет ранее отправленный HTTP-заголовок.
getHeader (string $header): ?string
Возвращает отправленный HTTP-заголовок или null, если его нет.
Параметр нечувствителен к регистру.
$pragma = $httpResponse->getHeader('Pragma');
getHeaders(): array<string, string>
Возвращает все отправленные HTTP-заголовки ассоциативным массивом.
$headers = $httpResponse->getHeaders();
echo $headers['Pragma'];
setContentType (string $type, ?string $charset=null)
Меняет заголовок Content-Type.
$httpResponse->setContentType('text/plain', 'UTF-8');
redirect (string $url, int $code=self::S302_Found): void
Перенаправляет на другой URL. Не забудьте затем завершить скрипт.
$httpResponse->redirect('http://example.com');
exit;
setExpiration (?string $expire)
Задаёт срок действия HTTP-документа с помощью заголовков
Cache-Control и Expires. Параметр – это либо временной интервал
(текстом), либо null, который отключает кеширование.
// кеш браузера истекает через час
$httpResponse->setExpiration('1 hour');
sendAsFile (string $fileName)
Ответ будет скачан через диалог Сохранить как с указанным именем. Сам файл при этом не отправляется.
$httpResponse->sendAsFile('invoice.pdf');
setCookie (string $name, string $value,
$expire, ?string $path=null, ?string $domain=null, ?bool $secure=null, ?bool $httpOnly=null,
SameSite|string $sameSite='Lax', bool $partitioned=false)
Отправляет cookie. Значения параметров по умолчанию:
$path |
'/' |
cookie доступна для всех путей в рамках (под)домена (настраивается) |
$domain |
null |
то есть доступна для текущего (под)домена, но не для его поддоменов (настраивается) |
$secure |
auto |
true, если сайт работает по HTTPS, иначе false (по умолчанию во
фреймворке; у голого класса по умолчанию false)
(настраивается) |
$httpOnly |
true |
cookie недоступна для JavaScript |
$sameSite |
'Lax' |
cookie может не отправляться при доступе с другого источника |
$partitioned |
false |
является ли cookie секционированной, см. ниже (начиная с v3.4) |
Значения по умолчанию для параметров $path, $domain и
$secure можно изменить в конфигурации.
Срок действия передаётся количеством секунд, текстовым интервалом
или датой либо объектом DateTimeInterface. Значение null создаёт
сессионную cookie, которую браузер выбрасывает при закрытии. Nette
отправляет срок действия и в атрибуте Expires, и в Max-Age.
$httpResponse->setCookie('lang', 'en', '100 days'); // истекает через 100 дней
$httpResponse->setCookie('lang', 'en', null); // сессионная cookie
Параметр $domain определяет, какие домены могут принимать cookie.
Если он не указан, cookie принимает тот же (под)домен, который её задал, но
не его поддомены. Если $domain указан, поддомены тоже включаются.
Поэтому указание $domain менее ограничительно, чем его отсутствие.
Например, при $domain = 'nette.org' cookie доступны и на всех поддоменах
вроде doc.nette.org.
Значение $sameSite можно передать перечислением
Nette\Http\SameSite: SameSite::Lax, SameSite::Strict или SameSite::None
(строковые значения 'Lax', 'Strict', 'None' тоже работают).
Если вы зададите SameSite::None, атрибут $secure включится
автоматически, потому что браузеры отвергают cookie с SameSite=None,
которая не является secure.
Секционированные cookie (CHIPS) дают cookie собственное отдельное
хранилище для каждого сайта верхнего уровня. Поэтому когда сторонний
сервис (например, встроенный виджет) устанавливает секционированную
cookie, браузер хранит отдельную копию для каждого сайта, на котором
виджет появляется, и эти копии нельзя связать между собой для
межсайтовой слежки. Включается это заданием $partitioned в true;
для этого требуется и атрибут $secure, поэтому он включается
автоматически.
$httpResponse->setCookie('theme', 'dark', '1 year', sameSite: SameSite::None, partitioned: true);
deleteCookie (string $name, ?string $path=null, ?string $domain=null, ?bool $secure=null): void
Удаляет cookie. Значения параметров по умолчанию:
$pathс областью действия на все каталоги ('/')$domainс областью действия на текущий (под)домен, но не на его поддомены$secureзависит от настроек в конфигурации
$httpResponse->deleteCookie('lang');
Nette\Http\Context
Объект Nette\Http\Context соединяет запрос и ответ вместе и помогает с HTTP-кешированием. Как сервис он не зарегистрирован, так что вы создаёте его сами. В презентерах обычно проще использовать метод lastModified(); контекст пригодится, когда вы отправляете ответ сами, например из собственного класса ответа.
isModified (string|int|\DateTimeInterface|null $lastModified=null, ?string $etag=null): bool
Определяет, изменилось ли содержимое со времени последнего
посещения клиента. Если вы передадите время последнего изменения, он
отправит заголовок Last-Modified; если вы передадите валидатор ETag
(короткую строку, обозначающую текущую версию содержимого, например
его хеш), он отправит заголовок ETag. Затем он сравнивает оба с
заголовками If-Modified-Since и If-None-Match, отправленными
браузером.
Если у браузера уже есть подходящая версия, метод задаёт код
304 Not Modified и возвращает false – в этом случае тело ответа
вообще не отправляйте. Иначе он возвращает true.
public function send(Nette\Http\IRequest $request, Nette\Http\IResponse $response): void
{
$context = new Nette\Http\Context($request, $response);
if ($context->isModified(filemtime($this->file), md5_file($this->file))) {
readfile($this->file);
}
}
Оба параметра необязательны. Если вы не знаете времени изменения содержимого, используйте только ETag, и наоборот.