オリジン サーバーと同じマシンに Nginx リバース プロキシがあります。プロキシが起点からの動的コンテンツをキャッシュするようにしたいのですが、クライアントがリソースを再検証するときに、起点をチェックせずに 304 をクライアントに返すだけでなく、プロキシも起点で再検証する必要があります。
たとえば、max-age を 60 秒に設定すると、プロキシは送信元を確認することなく、その期間 304 を喜んで返します。次のように、オリジンが毎秒新しい etag を生成するテストをセットアップしました (node.js エクスプレスを使用):
app.get('/dynamic/:file?', function(req, res){
var filename = req.params.file;
var filepath = path.join(__dirname, 'files', filename);
res.setHeader('Cache-Control', 'public, must-revalidate, proxy-revalidate, max-age=60, s-maxage=60');
res.setHeader('ETag', filename+etagCounter);
res.sendfile(filepath);
console.log('request', requestCounter++);
console.log('etag', etagCounter);
console.log('date', new Date().toISOString());
});
Nginx では、このリクエストを渡すルートは次のように構成されます。
location /cache/ {
access_log on;
add_header Vary "Accept-Encoding";
add_header X-AppServer $upstream_addr; # Backend Server / Port
add_header X-AppServer-Status $upstream_status; # Backend HTTP Status
add_header X-Cache $upstream_cache_status; # HIT / MISS / BYPASS / EXPIRED
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_cache one;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_pass http://localhost:4444/;
}
クライアントが Express と直接通信すると、Express から 304 が返されますが、Express の間にプロキシがある場合、304 が Nginx に返されることはありません。Nginx はキャッシュからサービスを提供し、max-age が経過したときにオリジンからリソースを取得するだけです。
確実に etag の更新間隔を 60 秒に、max-age を 1 に設定します。その結果、Nginx はオリジンから毎秒新しいリソースを取得し (再検証を行わないため、200 応答)、304 を返します。 etag が 60 秒後に変更されるまで、クライアントに送信します。
私の結論は、Nginx がオリジン サーバーで再検証されることは決してないということです。max-age に従ってリソースが必要であると判断した場合はいつでも、リソースの新しいコピーを取得するだけです。
私がやりたいことをする方法はありますか?proxy-revalidate ヘッダーを尊重していませんか、それとも正しいアプローチをとっていませんか?
[編集]
それ以来、ここで答えを見つけました。この記事から、2 つのソリューションを作成します。
1) キャッシュされた応答の must-revalidate/proxy-revalidate は、リクエストで max-age=0 を受け取ったときに nginx が再検証をトリガーするのに十分なはずです。
2) クライアントが CC ヘッダーで「no-cache」を送信する場合、プロキシは確実にオリジンで再検証を行う必要があります。
私のテストから、両方が機能していないようです。たとえば、次のようなリクエストを行っています。
curl 'http://localhost:9088/cache/dynamic/image.jpg' -H 'If-None-Match: image.jpg0' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Host: localhost:9088' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Cache-Control: no-cache, max-age=0' -H 'Cookie: octane.sid=s%3AUa64F6fk2Pw0uwZ28e7OICyv.z2FNPYjQ7%2Fn%2F3vZGXV7B3QBYtqN%2FHzjV1e3XTuZcnmwduE4SBFEPDv3zE3zRuA4Ae705RtI6Z%2BBrqJyMveSjNA' -H 'Connection: keep-alive' -H 'If-Modified-Since: Thu, 06 Sep 2012 09:21:53 GMT' --compressed -I
が含まれています-H 'Cache-Control: no-cache, max-age=0'
が、オリジンをチェックせずにnginxキャッシュからコンテンツを提供しています。
この点でNginxの動作は悪いですか? バージョン1.5.4を使用しています