05/29/2018, 8:07 PM GMT+9

nginxでproxy_passのtrailing slashには特に気をつけるべきという話

以前お話したtrailing slashについて

http://blog.cosnomi.com/archives/475

意味上の違いはあるけど、実質あまり気にしなくても大丈夫だよねという感じだった。しかし、nginx の設定をしていると見事にハマったのでメモとして残しておきたい。

今回は比較するのは以下の Case1 と Case2

# Case 1
location /japan/ {
  proxy_pass http://example.jp/
}

# Case 2
location /japan/ {
  proxy_pass http://example.jp
}

実際どうなるか

Case1: Trailing Slash あり

http://example.com/japan/hoge にアクセスした場合、proxy_passによってhttp://example.jp/hoge に転送される。http://example.com/japan/ へのアクセスは http://example.jp/ に転送されるはず。

example.jp 側ではわざわざ/japan を含めて処理してやる必要がないので、こちらのほうが適切な気がする。というか、特殊な場合を除いて Trailing Slash ありで良さそう。

Case2: Trailing Slash なし

http://example.com/japan/hoge にアクセスした場合、proxy_passによって http://example.jp/japan/hoge に転送される。http://example.com/japan/ へのアクセスはhttp://example.jp/japan/ に転送されるはず。

つまり、転送先のサーバーでは/japan も含めて処理する必要がある。そうしないと、404 になってしまう。しかし、転送先のサーバーは自分の担当するルートは/japanであるということを知っているべきなのだろうか。多くの場合はそうでないと思う。だから、通常は Case1 のほうが好まれるはず。ただし、もともと/japan を含めて処理していたという場合は、こちらを用いる必要がある。

今回、私はもともと/japan(のような文字列)を含めて処理をしていたシステムを結合させるのに Case1 のような書き方をしてしまったので、404 になっていた。

Trailing Slash なしは URI とは言わない?

公式ドキュメント(http://nginx.org/en/docs/http/ngxhttpproxymodule.html#proxypass)によると、「If proxy_pass is specified without a URI,」が「trailing slash のない場合」と対応しているように見える。つまり、trailing slash のない場合はそもそも URI ではないということなのだろうか。

公式ドキュメントの解説

nginx の公式ドキュメントでどのような記述になっているか見てみよう。というか、こちらのほうを最初に紹介するべきだったかもしれない。

A request URI is passed to the server as follows:

  • If the  proxy_pass  directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

    location /name/ {
        proxy_pass http://127.0.0.1/remote/;
    }
  • If  proxy_pass  is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

    location /some/path/ {
        proxy_pass http://127.0.0.1;
    }

つまり、trailing slash あり(狭義のURI)の場合、location に合致する部分は proxy_pass で指定された URL に置き換えられる

一方、trailing slash なし(広義の?不完全な?URI)の場合、リクエスト URI はそのままサーバーに送られることとなる。

まとめ

  • 普通に pass したいときは末尾の/をつけること
  • 以前からのシステムを結合させるときなど特殊な場合は末尾の/を抜くべきなこともある

Cosnomi
Cosnomi

コンピュータ(Web, 機械学習など)が好きな医学部生

Twitter / GitHub