HTTP レスポンス
Nette は HTTP のレスポンスを、分かりやすい API を持つオブジェクトに包みます。
HTTP のレスポンスは Nette\Http\Responseオブジェクトが表します。Nette
を使っているなら、このオブジェクトはフレームワークが自動的に作るので、dependency
injectionで渡してもらえます。プレゼンターでは $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)
Cache-Control と Expires のヘッダーで HTTP
の文書の有効期限を設定します。パラメータは時間の間隔(文として)か、キャッシュを切る
null です。
// ブラウザのキャッシュは 1 時間で切れます
$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)
クッキーを送ります。パラメータの既定値です。
$path |
'/' |
クッキーは(サブ)ドメインのすべてのパスで使えます (設定できます) |
$domain |
null |
つまり今の(サブ)ドメインでは使えますが、そのサブドメインでは使えません (設定できます) |
$secure |
auto |
サイトが HTTPS で動いていれば true、そうでなければ
false(フレームワークの既定。クラス単体では
false)(設定できます) |
$httpOnly |
true |
クッキーは JavaScript から触れません |
$sameSite |
'Lax' |
別オリジンからのアクセスのときクッキーが送られないことがあります |
$partitioned |
false |
クッキーを分割するかどうか。下をご覧ください (v3.4 以降) |
$path、$domain、$secure のパラメータの既定値は設定で変えられます。
有効期限は秒数、間隔や日付の文、あるいは DateTimeInterface
オブジェクトとして渡します。値 null
はセッションのクッキーを作り、ブラウザを閉じると捨てられます。Nette は有効期限を
Expires と Max-Age の両方の属性で送ります。
$httpResponse->setCookie('lang', 'en', '100 days'); // 100 日で切れます
$httpResponse->setCookie('lang', 'en', null); // セッションのクッキー
$domain
のパラメータは、どのドメインがクッキーを受け取れるかを決めます。指定しなければ、クッキーはそれを設定したのと同じ(サブ)ドメインだけが受け取り、そのサブドメインは受け取りません。$domain
を指定すると、サブドメインも含まれます。ですから $domain
の指定は、省くよりも制限が緩くなります。たとえば $domain = 'nette.org'
なら、クッキーは doc.nette.org のようなすべてのサブドメインでも使えます。
$sameSite の値は Nette\Http\SameSite の enum、つまり
SameSite::Lax、SameSite::Strict、SameSite::None として渡せます(文字列の値
'Lax'、'Strict'、'None' も使えます)。SameSite::None にすると
$secure の属性が自動的に有効になります。ブラウザは secure でない SameSite=None
のクッキーを拒むからです。
分割されたクッキー(CHIPS)は、最上位のサイトごとに自分だけの別の保管場所を持ちます。ですから第三者のサービス(埋め込まれたウィジェットなど)が分割されたクッキーを設定すると、ブラウザはそのウィジェットが現れるサイトごとに別々の複製を持ち、それらの複製はサイトをまたいだ追跡のために結び付けられません。有効にするには
$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
クッキーを消します。パラメータの既定値は次のとおりです。
$pathはすべてのディレクトリを範囲にします('/')$domainは今の(サブ)ドメインを範囲にし、そのサブドメインは含みません$secureは設定の内容によります
$httpResponse->deleteCookie('lang');
Nette\Http\Context
Nette\Http\Contextオブジェクトはリクエストとレスポンスを結び付け、HTTP のキャッシュを助けます。サービスとしては登録されていないので、自分で作ります。プレゼンターではふつう lastModified()メソッドを使うほうが簡単です。context は、たとえば自分のレスポンスのクラスからのように、自分でレスポンスを送るときに役立ちます。
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 だけを使い、その逆も同じです。