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, и наоборот.

версия: 4.x