nginx rewriteのlastとbreakの違い

nginx でリライトルールを書くには return または rewrite を使う。
rewrite を使った時の フラグ last break の違いがわかりにくかったので、簡単にメモ。

return を使ったリライト

syntax

  • return code [ text ] (ex. return 403return 404 "not found")
  • return code URL (ex. return 301 http://www.example.org$request_uri; )
  • return URL (ex. return http://www.example.org$request_uri; )code は 302

rewrite を使ったリライト

Apache の mod_rewrite に近い。

syntax

rewrite regex replacement [ flag ]

オプションの flag には以下の 4 つの中から指定可能

  • last – completes processing of current rewrite directives and restarts the process (including rewriting) with a search for a match on the URI from all available locations.
  • break – completes processing of current rewrite directives and non-rewrite processing continues within the current location block only.
  • redirect – returns temporary redirect with code 302; it is used if the substituting line begins with http:// (デフォルト)
  • permanent – returns permanent redirect with code 301

ex. rewrite ^ http://example.com/new-address.html? permanent;

最後2つの redirect permanent はいいとして last break の違いがわかりにくかったので、シンプルなリライトルールを書いて違いを確認してみた。

breakとlastの違いを確認

環境

OS は Cent6
nginx は 1.4.4 を利用

検証用設定

/etc/nginx/conf.d/default.conf の localhsot server の設定に location ルールを追加

    root   /usr/share/nginx/html;
    rewrite_log on;

    location /rewrite {
        rewrite ^/rewrite  /foo;
        rewrite ^/foo      /bar;
        add_header H-rewrite dummy;
    }

    location /last {
        rewrite ^/last     /foo last;
        rewrite ^/foo      /bar last;
        add_header H-last dummy;
    }

    location /break {
        rewrite ^/break    /foo break;
        rewrite ^/foo      /bar break;
        add_header H-break dummy;
    }

    location /foo {
        add_header H-foo dummy;
    }

    location /bar {
        add_header H-bar dummy;
    }

    location / {
        index  index.html index.htm;
        add_header H-index dummy;
    }

また、リダイレクト先のページも用意

# echo foo > /usr/share/nginx/html/foo
# echo bar > /usr/share/nginx/html/bar

ログ設定

rewrite 処理がログ出力されるようにする

/etc/nginx/conf.d/default.conf の server ディレククティブで rewrite_log on; にする。
次に /etc/nginx/nginx.conf でログ出力レベルを notice にする

error_log /var/log/nginx/error.log notice;

デフォルトの rewrite

レスポンスヘッダー

$ curl -D - http://localhost/rewrite
HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Sun, 16 Feb 2014 06:05:42 GMT
Content-Type: application/octet-stream
Content-Length: 4
Last-Modified: Sat, 15 Feb 2014 15:12:05 GMT
Connection: keep-alive
ETag: "52ff83c5-4"
H-bar: dummy
Accept-Ranges: bytes

bar

nginx log

2014/02/16 15:05:42 [notice] 21738#0: *4 "^/rewrite" matches "/rewrite", client: 127.0.0.1, server: localhost, request: "GET /rewrite HTTP/1.1", host: "localhost"
2014/02/16 15:05:42 [notice] 21738#0: *4 rewritten data: "/foo", args: "", client: 127.0.0.1, server: localhost, request: "GET /rewrite HTTP/1.1", host: "localhost"
2014/02/16 15:05:42 [notice] 21738#0: *4 "^/foo" matches "/foo", client: 127.0.0.1, server: localhost, request: "GET /rewrite HTTP/1.1", host: "localhost"
2014/02/16 15:05:42 [notice] 21738#0: *4 rewritten data: "/bar", args: "", client: 127.0.0.1, server: localhost, request: "GET /rewrite HTTP/1.1", host: "localhost"

/rewrite の location では rewrite を2回定義している
まず /rewrite を /foo にリライトし、2回目のリライトルールで /foo を /bar にリライトする
add_header は /bar location のもの(H-bar: dummy)が有効になっている

結果的に /bar にリクエストするのと同じレスポンスが返ってくる。

break rewrite

レスポンスヘッダー

$ curl -D - http://localhost/break
HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Sun, 16 Feb 2014 06:06:14 GMT
Content-Type: application/octet-stream
Content-Length: 4
Last-Modified: Sat, 15 Feb 2014 15:12:01 GMT
Connection: keep-alive
ETag: "52ff83c1-4"
H-break: dummy
Accept-Ranges: bytes

foo

nginx log

2014/02/16 15:06:14 [notice] 21738#0: *5 "^/break" matches "/break", client: 127.0.0.1, server: localhost, request: "GET /break HTTP/1.1", host: "localhost"
2014/02/16 15:06:14 [notice] 21738#0: *5 rewritten data: "/foo", args: "", client: 127.0.0.1, server: localhost, request: "GET /break HTTP/1.1", host: "localhost"

/break の location では rewrite を2回定義している。
まず /break を /foo にリライトする。
ここで break のおかげで、2回目の /foo から /bar へのリライトルールは適用されない。(break より後ろにある rewrite ルールは適用されない)

/break location ブロックで rewrite より後ろにある add_header は処理され、レスポンスヘッダーに "H-break: dummy" が付く。(break より後ろにある rewrite 以外のルールは適用される)
rewrite 先の /foo location の add_header は処理されていない。

last rewrite

/last の location では rewrite を2回定義している
/break location との違いは rewrite ルールのフラグが break ではなく last であること。

レスポンスヘッダー

$ curl -D - http://localhost/last
HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Sun, 16 Feb 2014 06:06:38 GMT
Content-Type: application/octet-stream
Content-Length: 4
Last-Modified: Sat, 15 Feb 2014 15:12:01 GMT
Connection: keep-alive
ETag: "52ff83c1-4"
H-foo: dummy
Accept-Ranges: bytes

foo

nginx log

2014/02/16 15:06:38 [notice] 21738#0: *6 "^/last" matches "/last", client: 127.0.0.1, server: localhost, request: "GET /last HTTP/1.1", host: "localhost"
2014/02/16 15:06:38 [notice] 21738#0: *6 rewritten data: "/foo", args: "", client: 127.0.0.1, server: localhost, request: "GET /last HTTP/1.1", host: "localhost"

/break と同じく、2回目の /foo から /bar へのリライトルールは適用されない。(last より後ろにある rewrite ルールは適用されない)
また、/break と異なり、/last location ブロックで last より後ろにある add_header も処理されない。
代わりに、リライト先の /foo location の add_header(H-foo: dummy)が処理されているる。(last  の rewrite に出くわすと、今いる location を抜けて rewrite 先の location に処理が移る)

References

Leave a comment