目次
画像などをBase64データにしてURLで受け渡す場合の注意点と対策例
BASE64は、バイナリデータを一定の規則に基づいてテキスト(文字)データに置き換える変換方式の一つです。
アルファベットの大文字(26文字)と小文字(26文字)、数字(10文字)、「+」「/」の2つの記号の64種類の英数字のみを用いてデータを表現します。
テキストしか渡せないURLパラメータなどによく使われますが、JavaScriptでBase64にエンコードした画像データをWeb-APIにURLパラメータで渡すような場合に、ちょっと落とし穴というか注意すべき点があります。
Base64テキストがそのままURLパラメータにできない理由
だから、URLパラメータにそのまま渡せるような気がします。
でも・・うまくいきません。
なぜかというと、URL内で特別な意味を持つ、「+」 と「 /」 がBase64テキストに含まれるからです。
特に「+」が問題です。
そのままURLのパラメータに渡すと、勝手に「+」が空白に置き換えられます。
なので、サーバー側でBase64からデコードすると、「異常な画像データで例外が発生」してしまいます。
ユーザサイドからみると「500 Internal Server Error」なんかになるわけです。
Base64テキストをURLパラメータに渡せるようにするサンプル
Base64エンコードテキストに含まれる「/」や「+」は悪さをしない別の文字に置き換えて、URLパラメータに渡し、受取側(サーバー側)で元に戻してやる処理が必要です。
たとえば、「/」を「!」に、「+」を「-」に置き換えるとかです。
この置換文字のヒントは、Wikipediaからもらいました。
Pythonで、GETで受け取ったBase64フォーマットテキスト「img_quoted」に含まれる「/」や「+」を、悪さをしない別の文字に置き換える処理を書くと、こんな感じです。
img_quoted = request.GET.get(key="img", default="")
encode_dic = {'!': '/', '-': '+'}
encode_table = str.maketrans(encode_dic)
image_unquoted = img_quoted.translate(encode_table)
str.maketransの使い方については、こちらにまとめてます。
同じようなことを、JavaScript側で書くとすると
var translated = this.images_decodable[0].replace(/\//g, '!').replace(/\+/g, '-')
みたいな感じですかね。
JavaScriptで画像をBase64変換したものも注意が必要
画像ファイルをBase64エンコードしてWebAPIに渡すケースがあります。
そのようなケースで、JavaScriptでBase64エンコードする場合の注意点です。
JavaScriptで画像ファイルを読んで、Base64エンコードテキストにしたものは、そのままでは、Python側でデコードできないデータになっていることがあります。
どういうことかというと。
ドロップされた画像ファイルを「readAsDataURL(file)」とかで読んで、reader.resultでBase64エンコードした結果を受け取る・・というのが、JavaScript側でBase64エンコードする「よくある方法」なのですが。
この時、reader.resultで受け取れるBase64フォーマットには、<img>タグで表示するために必要な「data:image/jpeg;base64,」とか「data:image/png;base64,」がくっついているからなのです。
HTML表示には、とても便利なのですが、そのままでは100%デコードに失敗します。
なので。
サーバー側でデコードさせるためには、事前にそれを削除しておく必要があるというわけです。
JavaScriptで簡単に書くなら
if (fileList[i].type === 'image/jpeg') {
this.images_decodable.push(String(res).replace('data:image/jpeg;base64,', ''))
} else {
this.images_decodable.push(String(res).replace('data:image/png;base64,', ''))
}
みたいに、ファイルのタイプで判断して、頭の余分な文字列を''に置き換えるか感じになるかと思います。
今回はこんなところで。
ではでは。