@ledsun blog

無味の味は佳境に入らざればすなわち知れず

相対URLの解決

URL: URL() コンストラクター - Web API | MDN を使うと、基準になるURLからの相対パスを解決したURLが得られます。 例えば、次のように使います。

// ベース URL:
let baseUrl = "https://developer.mozilla.org";

new URL("ja/docs", baseUrl);
// => 'https://developer.mozilla.org/ja/docs'

このコンストラクターの挙動を試しているときに、次の例を考えました。

new URL('a.rb', 'http://exapmle.com/lib').toString()
// => 'http://exapmle.com/a.rb'

このとき http://exapmle.com/lib/a.rb となって、libディレクトリの中を参照して欲しいのではないでしょうか?

これはJavaScript特有の動作なのでしょうか?

Rubyでも試してみました。 RubyではURLの結合には URI.join を使います。

require 'uri'

URI.join(URI.parse('http://exapmle.com/lib'), 'a.rb')
# => #<URI::HTTP http://exapmle.com/a.rb>

やはり lib が消えます。 統一された動作です。 もしかしてこれはどこかで決まっているのでしょうか?

るりまに以下の説明がありました。

[RFC2396] の Section 5.2 の仕様に従って連結します。

というわけでRFCを見てます。 https://datatracker.ietf.org/doc/html/rfc2396#autoid-33

6) If this step is reached, then we are resolving a relative-path reference. The relative path needs to be merged with the base URI's path. Although there are many ways to do this, we will describe a simple method using a separate string buffer.

 a) All but the last segment of the base URI's path component is
    copied to the buffer.  In other words, any characters after the
    last (right-most) slash character, if any, are excluded.

base URIの最後のスラッシュ以降に何かあれば、その部分はバッファ(解決後のURLを結合するための場所)に入れないそうです。 なるほど、JavaScriptRubyもこの動きをしていそうです。

この記事を書いている途中で気がつきました。 URLは文字列で、ファイルシステムではありません。 http://exapmle.com/lib がファイルかディレクトリかという区別は、文字列から読み取るしかありません。 すると

  • /で終わるのが、ディレクト
  • /の後ろに文字列が続いていたらファイル

みたいな、単純な方法で区別するしかない気がしてきました。 libディレクトリに見えるのは、背景知識があるから人間に判別できているっぽいです。

RubyJavaScript、ファイルとURLの間を行ったり来たりしていると、自分がどこにいるのか、よく見失います。