Nginx で 404 をキャッシュさせない
nginx で 404をキャッシュさせないようにする場合、
add_header Cache-Control "no-cache, no-store"; return 404 "not found";
と設定しても、Cache-Control ヘッダが付与されません。
Module ngx_http_headers_module を見ると、
Adds the specified field to a response header provided that the response code equals 200, 201, 204, 206, 301, 302, 303, 304, or 307. A value can contain variables.
とあるので、add_header で 404 response に Cache-Control ヘッダを追加できません。
404 で Cache-Control ヘッダを追加する場合は、HttpHeadersMoreModule - Nginx Community を使えば可能になります。
HttpHeadersMoreModule はデフォルトでは入っていないので、ビルド時に add-module で追加する必要があります。
以下、設定ファイルと curl の結果です。
設定ファイル
server { listen 80; server_name localhost; location =/404 { default_type application/json; try_files $uri =404; error_page 404 = @notfound; } location @notfound { more_set_headers -s 404 "Cache-Control: no-cache, no-store"; return 404 " "; } }
404
$ curl "http://localhost/404" $ curl -I "http://localhost/404" HTTP/1.1 404 Not Found Server: ngx_openresty/1.4.3.6 Date: Fri, 10 Oct 2014 07:25:32 GMT Content-Type: application/octet-stream Content-Length: 1 Connection: keep-alive Cache-Control: no-cache, no-store
return 404 で半角スペース1文字を返しているのは、
空文字だとデフォルトの 404 ページを返すようになっているからです。
おそらく https://github.com/nginx/nginx/blob/master/src%2Fhttp%2Fngx_http_script.c#L1355-1373 が該当のコードだと思うのですが、
code->text の長さを見ているので、空文字だと上書きされないのだと思います。
もし、空の response を返したい場合は、空の html を用意してそれを返すようにするか、
HttpEchoModule - Nginx Community を使って、
echo -n "";
とすれば、空の response を返せます。
以下が、実験時の設定ファイルと結果です。
設定ファイル
server { listen 80; server_name localhost; location =/echo { try_files $uri =404; error_page 404 =404 @echo; } location @echo { more_set_headers -s 404 "Cache-Control: no-cache, no-store"; echo -n ""; } location =/empty.html { try_files $uri =404; error_page 404 =404 @empty; } location @empty { more_set_headers -s 404 "Cache-Control: no-cache, no-store"; root /var/www/html; index empty.html; } }
echo 結果
$ curl "http://localhost/echo" $ curl -I "http://localhost/echo" HTTP/1.1 404 Not Found Server: ngx_openresty/1.4.3.6 Date: Fri, 10 Oct 2014 10:33:10 GMT Content-Type: application/octet-stream Connection: keep-alive Cache-Control: no-cache, no-store
empty.html 結果
$ curl "http://localhost/empty.html" $ curl -I "http://localhost/empty.html" HTTP/1.1 404 Not Found Server: ngx_openresty/1.4.3.6 Date: Fri, 10 Oct 2014 10:34:27 GMT Content-Type: text/html Content-Length: 0 Connection: keep-alive ETag: "5437b19d-0" Cache-Control: no-cache, no-store
一見同じですが、echo の方は、Content-Length ヘッダがついておらず、
$body_bytes_sent が 5 となっていました。
default_type application/octet-stream; としていると、
content-type がないので octet-stream になりますが、それが原因なようでした。
content-type を text/html になるように設定すれば、echo の方でも $body_bytes_sent が 0 になりました(Content-Length はつかないままでした)。
以上のことから、404 で空の response を返す場合は、
- 空の html を返す
- content-type を text/html(application/octet-stream 以外?)にして echo -n "" を使う
とする必要があります。