URIの最後にあるスラッシュ
本記事では、URI末尾の”/”、トレイリングスラッシュについてまとめます。
主にApache HTTP Serverの仕様について記載しますが、NGINXや相対パスとの関連性についても参考情報を記載しておきます。
本記事の目的
- URIの最後にある”/”(トレイリングスラッシュ)について理解する。
基本
Apache HTTP Serverにおけるトレイリングスラッシュの扱い
デフォルト動作
デフォルトでは、リクエストされたURIhttps://server/dir
の”dir”がディレクトリである場合、https://server/dir/
にリダイレクトします。
つまり、リクエストしたURIの末尾に”/”が付与されたURIに再アクセスするようApache HTTP Serverから301応答が送信されます。
この末尾の”/”がトレイリングスラッシュです。
このリダイレクト動作はtrailing slash redirectと呼ばれます。
DirectorySlash
ディレクティブ
trailing slash redirectは、mod_dirのDirectorySlashディレクティブにより設定されます。
DirectorySlash
ディレクティブはデフォルトで”On”です。特に理由が無ければ変更する必要性はありません。
URIにトレイリングスラッシュを含めることで、以下の動作になる旨の説明があります。
-
最終的に正しいURLにアクセスできる
(The user is finally requesting the canonical URL of the resource.) -
mod_autoindex
が正しく動作する
(mod_autoindex
works correctly. Since it doesn’t emit the path in the link, it would point to the wrong path.)Options +Indexes
使用時に生成される自動インデックスページ内のリンクは相対パスのようで、トレイリングスラッシュが必要(相対パスに関しては後述)
-
DirectoryIndex
ディレクティブが正しく動作する
(DirectoryIndex
will be evaluated only for directories requested with trailing slash.) -
相対URL参照が正しく動作する
(Relative URL references inside html pages will work correctly.)
DirectorySlash
をOffにした場合、トレイリングスラッシュの無いURIへのアクセス時に、Options +Indexes
が有効だとディレクトリ内のファイル一覧を表示させてしまうというセキュリティ上の注意が必要な点についても触れられています。この場合、DirectoryIndex
が設定されていたとしても、トレイリングスラッシュが無いので動作しません。
トレイリングスラッシュを考慮する際の観点
以下のような観点で、トレイリングスラッシュの扱いを考慮する必要がありそうです。
- Webサーバに配置するコンテンツやアプリケーションがトレイリングスラッシュの有無により影響を受けるか
- リバースプロキシ等のWeb環境全体がトレイリングスラッシュの有無により影響を受けるか
- リクエストに含まれるURIがディレクトリかどうかを区別した動作をさせたいか
基本的には、できるだけUser Agentに近いフロント側でトレイリングスラッシュの有無による影響を吸収できる構成の方が、管理しやすいと思います。
そのための対応として、リダイレクトやプロキシ時のパス変換等が考えられます。
詳細
NGINXの場合
NGINXの方は、location
ブロックで指定されたパスにマッチするリクエストは、トレイリングスラッシュが省略されていてもトレイリングスラッシュ付きのURIにリダイレクトされるようです。
In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended.
Module ngx_http_core_moduleより
このリダイレクト動作を回避したい場合の設定例として、トレイリングスラッシュ無しのURIに完全一致する=
構文による定義を追加したものが記載されています。
location /user/ { … }
←もともとの設定
location = /user { … }
←追加した設定
それ以外のリクエストに対しては、自動的にトレイリングスラッシュ付きのURIにリダイレクトさせないようなので、リダイレクトさせたい場合にはrewrite
による設定等が必要そうです(例:rewrite ^([^.]*[^/])$ $1/ permanent;
)。
ただし、リクエストされたパスに一致するリソースがファイルなのかディレクトリなのかを判別してリダイレクトの有無を制御するような設定があるのかは分かりませんでした。
あと、リバプロ構成のNGINXで色々検証されている記事があって参考になりそうなので記載しておきます。
トレイリングスラッシュの有無によるURIにおける相対パスの扱い
あるURI(base URI)で表示されたコンテンツ内にある、相対パス./link
を指すリンクにアクセスした際のURIは以下のようになります。
Webブラウザでリンクをクリックした際、リクエスト作成のためブラウザが生成するURIのことです。
-
トレイリングスラッシュ無し
- base URI:
https://testnap1.jp/dir/foo
- 相対パス
./link
にアクセス時のURI:https://testnap1.jp/dir/link
- トレイリングスラッシュが無いことで、
foo
は無視され、dir
の下にあるリソースにアクセスする
- base URI:
-
トレイリングスラッシュあり
- base URI:
https://testnap1.jp/dir/foo/
- 相対パス
./link
にアクセス時のURI:https://testnap1.jp/dir/foo/link
- トレイリングスラッシュがあることで、
foo
の下にあるリソースにアクセスする
- base URI:
上記に関し、RFC3986の5.2に詳細な仕様があります。
URI Resolution and Trailing Slashesにも詳しい説明があります。
RFC3986の5.2.3の相対パスのマージに関する記載によると、base URIに対して以下のようにパスが生成されることになっています。
- base URIがpathを持たない場合、”/”の後に相対パスを連結したパス
- 例:base URI:
https://testnap1.jp/
であれば、パスは/相対パス
- 例:base URI:
- base URIの最後のセグメントに相対パスを付与したURI
具体的には、以下のいずれか- base URIのpathの最も右にあるスラッシュより後にある文字は全て取り除いたもの
- 例:base URI:
https://testnap1.jp/dir/foo
であれば、パスは/dir/相対パス
- 例:base URI:
- base URIのpathがスラッシュを含まない場合、そのpath全体を取り除いたもの
- 例:(不明…pathがemptyでなく、かつスラッシュを含まないという例の見当がつきませんでした。ちなみに”?var=1″はpathでなくquery)
- base URIのpathの最も右にあるスラッシュより後にある文字は全て取り除いたもの