朝から昼寝

ITや身近な小ネタをちょこちょこ整理

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: https://testnap1.jp/dir/foo/ 
    • 相対パス./linkにアクセス時のURI: https://testnap1.jp/dir/foo/link
    • トレイリングスラッシュがあることで、fooの下にあるリソースにアクセスする

上記に関し、RFC3986の5.2に詳細な仕様があります。
URI Resolution and Trailing Slashesにも詳しい説明があります。

RFC3986の5.2.3の相対パスのマージに関する記載によると、base URIに対して以下のようにパスが生成されることになっています。

  • base URIがpathを持たない場合、”/”の後に相対パスを連結したパス
    • 例:base URI: https://testnap1.jp/であれば、パスは/相対パス
  • base URIの最後のセグメントに相対パスを付与したURI
    具体的には、以下のいずれか
    • base URIのpathの最も右にあるスラッシュより後にある文字は全て取り除いたもの
      • 例:base URI: https://testnap1.jp/dir/fooであれば、パスは/dir/相対パス
    • base URIのpathがスラッシュを含まない場合、そのpath全体を取り除いたもの
      • 例:(不明…pathがemptyでなく、かつスラッシュを含まないという例の見当がつきませんでした。ちなみに"?var=1"はpathでなくquery)