ブラウザキャッシュメカニズム
Last-Modifiedによるキャッシュ検証
HTTPヘッダのLast-Modifiedフィールドを使用して、ブラウザが保存しているキャッシュが最新かを確認します。サーバー側でファイルの最終更新日時と比較し、変更がなければ304 Not Modifiedを返します。
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');
http.createServer((req, res) => {
const { pathname } = url.parse(req.url, true);
const filePath = path.join(__dirname, pathname);
fs.stat(filePath, (err, stats) => {
if (err) {
return sendError(res);
}
const ifModifiedSince = req.headers['if-modified-since'];
const lastModified = stats.ctime.toGMTString();
if (ifModifiedSince === lastModified) {
res.writeHead(304);
res.end();
} else {
sendFile(req, res, filePath, stats);
}
});
}).listen(8080);
function sendError(res) {
res.end('Not Found');
}
function sendFile(req, res, filePath, stats) {
res.setHeader('Content-Type', mime.getType(filePath));
res.setHeader('Last-Modified', stats.ctime.toGMTString());
fs.createReadStream(filePath).pipe(res);
}
ETagによるキャッシュ検証
ETagは、リソースの内容に基づいた一意の識別子を生成し、キャッシュの検証に使用します。リソース内容が変更された場合のみETagが変更されるため、より正確なキャッシュ制御が可能です。
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');
const crypto = require('crypto');
http.createServer((req, res) => {
const { pathname } = url.parse(req.url, true);
const filePath = path.join(__dirname, pathname);
fs.stat(filePath, (err, stats) => {
if (err) {
return sendError(res);
}
const ifNoneMatch = req.headers['if-none-match'];
const readStream = fs.createReadStream(filePath);
const hash = crypto.createHash('md5');
readStream.on('data', (data) => {
hash.update(data);
});
readStream.on('end', () => {
const etag = hash.digest('hex');
if (ifNoneMatch === etag) {
res.writeHead(304);
res.end();
} else {
sendWithETag(res, filePath, etag);
}
});
});
}).listen(8080);
function sendError(res) {
res.end('Not Found');
}
function sendWithETag(res, filePath, etag) {
res.setHeader('Content-Type', mime.getType(filePath));
res.setHeader('ETag', etag);
fs.createReadStream(filePath).pipe(res);
}
Cache-Controlによるキャッシュ有効期限の設定
Cache-Controlヘッダを使用して、キャッシュの有効期間や振る舞いを指定します。max-ageで指定した秒数だけブラウザがキャッシュを保持できます。
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');
http.createServer((req, res) => {
const { pathname } = url.parse(req.url, true);
const filePath = path.join(__dirname, pathname);
fs.stat(filePath, (err, stats) => {
if (err) {
return sendError(res);
}
sendWithCacheControl(res, filePath);
});
}).listen(8080);
function sendError(res) {
res.end('Not Found');
}
function sendWithCacheControl(res, filePath) {
res.setHeader('Content-Type', mime.getType(filePath));
res.setHeader('Cache-Control', 'max-age=30');
fs.createReadStream(filePath).pipe(res);
}
Cache-Controlの主なディレクティブ:
- private:クライアントのみがキャッシュ可能
- public:クライアントとプロキシがキャッシュ可能
- max-age:指定された秒数だけキャッシュが有効
- no-cache:サーバーで再検証が必要
- no-store:キャッシュ不可