PSI Labs RSS feed

Etag と Last-modified ヘッダを使って動的コンテンツでもブラウザキャッシュさせる

こんにちは、tomitaです。

一般的なwebサーバでは、静的ファイルに「Etag」「Last-Modified」ヘッダが付加され、サーバ <=> ブラウザ間で適切なキャッシュコントロールが行われます。

(参考:HTTP ETag - Wikipedia)

しかし、PHP 等で生成した動的コンテンツには上記ヘッダが付加されないため、常に最新のデータがサーバから送られてきます。

当然動的ページなので下手にキャッシュされると困るのですが、更新頻度の低い動的ページではコンテンツキャッシュさせたいことがあります。

その場合は以下サンプルプログラムのように「Etag」「Last-Modified」ヘッダを生成・送信します。

<?php

header( "Content-Type: text/plain; charset=UTF-8" );

// Last-modified と ETag 生成
$last_modified = gmdate( "D, d M Y H:i:s T", filemtime( __FILE__ ) );
$etag = md5( $last_modified . __FILE__ );

// ヘッダ送信
header( "Last-Modified: {$last_modified}" );
header( "Etag: {$etag}" );

// リクエストヘッダの If-Modified-Since と If-None-Match を取得
$if_modified_since = filter_input( INPUT_SERVER, 'HTTP_IF_MODIFIED_SINCE' );
$if_none_match = filter_input( INPUT_SERVER, 'HTTP_IF_NONE_MATCH' );

// Last-modified または Etag と一致していたら 304 Not Modified ヘッダを返して終了
if ( $if_modified_since === $last_modified || $if_none_match === $etag ) {
  header( 'HTTP', true, 304 );
  exit;
}

// 何か時間のかかる処理
sleep(2);
echo "Hello!!";
exit;

サンプルプログラムでは実行ファイル更新時刻と実行ファイルパスを使って Etag を生成していますが、そのリクエストで一意となる Etag を生成すればよいので、リクエストURIなどを使ってもいいと思います。

以下、実際の動作サンプルです。初回表示時は 2秒待たされてから「Hello!!」が表示されますが、2回目以降はすぐに「Hello!!」が表示されることがわかります。

etag sample script

キャッシュが使えるところはなるべく使って、サーバ負荷軽減・回線帯域を節約していきたいですね。

それでは~