PayPal IPN 機能を実装しようとしています。基本的なプロトコルは次のとおりです。
- クライアントは私のサイトから PayPal のサイトにリダイレクトされ、支払いが完了します。彼は自分のアカウントにログインし、支払いを承認します。
- PayPal がサーバー上のページを呼び出し、詳細を POST として渡します。詳細には、人の名前、住所、支払い情報などが含まれます。
- 上記で渡されたすべてのパラメーターと、値が「_notify-validate」の「cmd」と呼ばれる追加のパラメーターを返す処理ページから、PayPal のサイトの URL を内部的に呼び出す必要があります。
PayPal から送信されたパラメーターを urllib.urlencode しようとすると、次のようになります。
While calling send_response_to_paypal. Traceback (most recent call last):
File "<snip>/account/paypal/views.py", line 108, in process_paypal_ipn
verify_result = send_response_to_paypal(params)
File "<snip>/account/paypal/views.py", line 41, in send_response_to_paypal
params = urllib.urlencode(params)
File "/usr/local/lib/python2.6/urllib.py", line 1261, in urlencode
v = quote_plus(str(v))
UnicodeEncodeError: 'ascii' codec can't encode character u'\ufffd' in position 9: ordinal not in range(128)
urlencode が ASCII エンコーディングを行うこと、および場合によっては、ユーザーの連絡先情報に非 ASCII 文字が含まれることがあることを理解しています。これは理解できます。私の質問は、urllib2.urlopen(req) (または他の方法) を使用して URL に POST するために非 ASCII 文字をエンコードする方法です。
詳細:
PayPal の元のリクエストのパラメーターを次のように読み取りました (GET はテスト用です)。
def read_ipn_params(request):
if request.POST:
params= request.POST.copy()
if "ipn_auth" in request.GET:
params["ipn_auth"]=request.GET["ipn_auth"]
return params
else:
return request.GET.copy()
処理ページから PayPal にリクエストを送り返すために使用するコードは次のとおりです。
def send_response_to_paypal(params):
params['cmd']='_notify-validate'
params = urllib.urlencode(params)
req = urllib2.Request(PAYPAL_API_WEBSITE, params)
req.add_header("Content-type", "application/x-www-form-urlencoded")
response = urllib2.urlopen(req)
status = response.read()
if not status == "VERIFIED":
logging.warn("PayPal cannot verify IPN responses: " + status)
return False
return True
明らかに、問題が発生するのは、誰かの名前、住所、または PayPal 支払いに使用されるその他のフィールドが ASCII の範囲に収まらない場合のみです。