背景
サービスに未登録のユーザーが会員登録をするためのページとして以下を用意しました。
## routes.rb get "entry/:access_key"
※ Railsでの実装例
access_key
とは、認証のためサービスが一時的に発行したトークンです。
access_key = SecureRandom.base64
さて、上記のページにアクセスをするとき、数回に一度404エラーになるときがありました。
はじめに結論
base64で生成される文字列にはURLに利用できない文字が含まれるため、urlsafeなbase64を使いましょう!
base64とは?
要点を箇条書きにするとこんな感じ。
- エンコード方式の1つ
- 半角英数字(a-zA-Z0-9)62文字と"+", "/"との64文字が使われる
- 文字の長さを整えるために末尾に"="を付ける(パディングする)こともある
メールを送るためのプロトコルSMTPで、画像や音声データをやり取りする際に使われていたようです。
cf. base64ってなんぞ??理解のために実装してみた - Qiita
Rubyでは、SecureRandom
クラスからbase64を使えます。
cf. module SecureRandom (Ruby 2.7.0 リファレンスマニュアル)
URLで使える文字・使えない文字
URI(URL)には、予約文字と非予約文字があります。
- 予約文字:区切り文字など特定の目的で使われる文字で、目的以外には利用不可
- 非予約文字:自由にURLに使用できる文字
cf. URIで使用できる文字 - CyberLibrarian
base64で利用される記号の"+", "/"は、どちらも予約文字にあたりますね。
つまり、今回の問題の問題は 「base64で生成される文字列の中に予約文字が含まれている」 場合に発生する、ということになります。
解決策
urlsafeなbase64があるので、そちらを使いましょう。 Rubyではこちらですね。
module SecureRandom (Ruby 2.7.0 リファレンスマニュアル)
仕組みとしては、予約文字の"+"を"-"に、”/"を"_"にそれぞれ変換することでURLで使えるようにしていました。
cf. urlsafe_encode64 (Base64) - APIdock
なお、urlsafeなbase64はRubyだけでなく、PHPやJavaなど他の言語でも対応してそうです。