私が歌川です

@utgwkk が書いている

nginx の $request_uri と $uri

nginxの $request_uri$uri は似ているけどちょっと違う。

$request_uri

$request_uri
full original request URI (with arguments)

  • クエリパラメータ付きのオリジナルのURI

$uri

$uri
current URI in request, normalized

The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files.

  • 正規化されたURI
  • リクエストの処理過程で $uri の値は変わりうる
  • クエリパラメータは付いてない

どのように正規化されるのか

locationディレクティブに書いてある。

The matching is performed against a normalized URI, after decoding the text encoded in the “%XX” form, resolving references to relative path components “.” and “..”, and possible compression of two or more adjacent slashes into a single slash.

  • パーセントエンコーディングの文字列をデコードする
  • 相対パスを解決する
  • merge_slashes on なら、2つ以上のスラッシュが隣接してたら1つにまとめる

見比べる

merge_slashes on;
log_format hoge "$request\trequest_uri:$request_uri\turi:$ur";
# 中略
access_log /var/log/nginx/access.log hoge;

のように設定して、/foo/bar/baz///こんにちは?hoge=2 にアクセスし、ログを見る*1

GET /foo/bar/baz///%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF?hoge=2 HTTP/1.1     request_uri:/foo/bar/baz///%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF?hoge=2      uri:/foo/bar/baz/\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF

たしかに $uri は正規化されてるしクエリパラメータが付いてない。

consistent hashでupstreamへのリクエストを振り分けるときや、アクセスログに記録するときにうまく使い分ける必要がありそう。

参考

*1:相対パスの部分はリクエストする前にChromecurlが解決しているようだった