Cosnomi

プログラミングをする医学生。物を作ること、自動化すること、今まで知らなかったことを知ることが好き。TypeScript書いたり、Pythonで機械学習したりなど。

Twitter / GitHub / Keybase
TOP >

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ではないということなのだろうか。

公式ドキュメントの解説

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したいときは末尾の/をつけること
  • 以前からのシステムを結合させるときなど特殊な場合は末尾の/を抜くべきなこともある

最後まで読んでいただきありがとうございます。コメントフォームは設置していません。訂正・意見・感想などはTwitter(@cosnomi)などへお願いします。
記事一覧へ