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 のヘッダーを送り、同じ名前の以前に送ったヘッダーを上書きします$valuenull なら、そのヘッダーは取り除かれます。

$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-ControlExpires のヘッダーで 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 は有効期限を ExpiresMax-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::LaxSameSite::StrictSameSite::None として渡せます(文字列の値 'Lax''Strict''None' も使えます)。SameSite::None にすると $secure の属性が自動的に有効になります。ブラウザは secure でない SameSite=None のクッキーを拒むからです。

分割されたクッキー(CHIPS)は、最上位のサイトごとに自分だけの別の保管場所を持ちます。ですから第三者のサービス(埋め込まれたウィジェットなど)が分割されたクッキーを設定すると、ブラウザはそのウィジェットが現れるサイトごとに別々の複製を持ち、それらの複製はサイトをまたいだ追跡のために結び付けられません。有効にするには $partitionedtrue にします。これには $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-SinceIf-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