location.hashにとある日本語が入るとFirefoxだけデコード失敗

location.hashにエンコードした日本語をセット→Firefoxだけデコードに失敗

いまさらながら location.hash と iframe を使ったクロスドメイン通信を書いてみました。

その際に Firefox で日本語の扱いに嵌った記録と解決法です。ちなみにバージョンは 38.0.5, Windows 版です、一応。

問題

エラーの起きていた部分を抜き出します。

location.hash = encodeURIComponent('日本語。');
decodeURIComponent(location.hash);

先のコードが Firefox だけデコードに失敗します。その際のエラーメッセージは URIError: malformed URI sequence でした。

もちろん、decodeURIComponent('#日本語。') とした場合は失敗しません。

詳しく見ていくと "。" でエラーが起きていました。(できましたらもうちょっと親切なエラーメッセージをお願いします…)

Firefox では、location.hash に日本語文字列等のエンコード済のものを渡しても勝手にデコードされます。

しかし "。" については "%u3002" にエスケープされます。この他には "、" がエスケープされました。

location.hash = encodeURIComponent('日本語。');

// location.hash
"#日本語%u3002"

解決

Gecko だけ unescape すると意図した動作を得られました。そこで現在はデコード部分を以下のようにしています。

X.UA[ 'Gecko' ] ? unescape( str ) : decodeURIComponent( str );

location.hash と日本語については kQuery の ofk 氏が素晴らしくまとめてくださっています。

今回はこの情報に Firefox だけ unescape を追加してね、ということでした。ではでは。

  • アンカーを付けたリンクを生成する場合は必ずencodeURIComponentでencodeして付与する。
  • location.hashに代入する場合も必ずencodeURIComponentでencodeして代入する。
  • 以上が守られたlocation.hashの値を取得する場合はFirefox以外はdecodeURIComponentでdecodeする。

解決してみればたったコレだけのことなのですが、他をいろいろと疑って大変でした…