[小ネタ] encodeURI と encodeURIComponent の違い


encodeURI / encodeURIComponent のエスケープ対象外

encodeURI は以下の文字がエスケープの対象外になります。

A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #

次に、encodeURIComponent は以下が対象外です。

A-Z a-z 0-9 - _ . ! ~ * ' ( )

紛らわしい

encodeURI と encodeURIComponent はどちらも正しいURI文字列を生成するためにエスケープ処理を行うという点で共通しています。

また、エスケープする対象の文字が違うということもドキュメントを当たれば確認できます。

ほぼ同じ処理を行うだけにユースケースが重なってしまっていて、いまいち正しい使い方がわかりません。

正しい使い方

encodeURI でエスケープ対象外になっている文字は簡単にいうと URI schemeshttps://en.wikipedia.org/wiki/List_of_URI_schemes)で使われている記号です。

そのため、以下の文字がエスケープの対象から除外されています。

https://example.com?hello=foo&world=bar#baz

encodeURIComponent はこのようなhttpを含む URI schemes で使われる記号も含めてURIのどこに含めても問題が起きない文字のみを除外してエスケープします。

したがって、URLの クエリ文字列 に指定するような文字列をエスケープしたい場合には encodeURIComponent を使います。

encodeURI を使うのは、クエリ文字列に事前に指定したURLのUTF-8文字をエスケープしたい場合に限定されます。

encodeURI を使うとOAuthの実装などで、コールバックURLをクエリ文字列に指定するとき不正なURLとなりエラーとなってしまいます。

// encodeURI だとエスケープされない
encodeURI("https://example.com?callback=https://example.com/auth/callback")
// => https://example.com?callback=https://example.com/auth/callback

// encodeURIComponent では URI schemes の文字までエスケープされる
const callbackURL = "https://example.com/auth/callback"
`https://example.com?callback=${encodeURIComponent(callbackURL)}`
// => https://example.com?callback=https%3A%2F%2Fexample.com%2Fauth%2Fcallback

ユースケースとしては、特定のクエリ文字列を指定する時にエスケープするのが通常だと思うので encodeURIComponent を使っておけば問題ないです。

結論

クエリ文字列では encodeURIComponent を使っとけばよろしい!

参考

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

https://en.wikipedia.org/wiki/List_of_URI_schemes