🏈

URLにデータを持たせる(Python)

2021/10/04に公開

結論

uriやクエリ変数にデータを持たせる時、altcharsを指定したbase64エンコードが使える。

import base64
binary_data = b'hogehoge'
str_data = base64.b64encode(binary_data, altchars=b'-:').decode('utf-8')
url = 'http://example.com/sample/{}'.format(str_data)

やりたかったこと

例えばメール認証の場合など、URLにハッシュキーを入れておき、ユーザーがアクセスするとハッシュキーを元にDBを参照して処理するといったことを行うと思います。
しかし、ケチケチデベロッパーとしては暗号化したデータをURLに持たせればテーブルを用意しなくて済むんじゃないか――みたいなことを考えたりしました。

暗号化の是非などは置いておくとして、他にもバイナリデータをURLに持たせたいというケースはあり得るような気がします。

base64標準でつまづく

バイナリデータをURLに持たせる際に普通にbase64エンコードしたものを使用したところ、ちょっと問題がありました。
通常のbase64エンコードでは、「/」(スラッシュ)や「+」(プラス)が含まれる可能性があるからです。データをURIに入れるにはスラッシュがルーティングの邪魔になります。クエリ変数に入れるにはプラスが空白文字として認識されてしまいます。

%2FなどにURLエンコードすれば大丈夫かな? とか思ったのですが、実際にはnginx+uwsgiを通してpythonのプログラムに入ってきた時点で、URLエンコードはデコード済みの状態となっていました。

回避方法が用意されていた

base64ライブラリの情報を見ると回避方法が用意されており、URLの一部として使えるように配慮されていました。

https://docs.python.org/ja/3/library/base64.html

altcharsというパラメータを指定することで、問題の「+」と「/」を別の文字に置き換えてくれるということです。
例えば代わりに「-」(ハイフン)と「:」(コロン)を使用することで、URLに使用可能な文字列となります。

Discussion