20

PayPal IPN 機能を実装しようとしています。基本的なプロトコルは次のとおりです。

  1. クライアントは私のサイトから PayPal のサイトにリダイレクトされ、支払いが完了します。彼は自分のアカウントにログインし、支払いを承認します。
  2. PayPal がサーバー上のページを呼び出し、詳細を POST として渡します。詳細には、人の名前、住所、支払い情報などが含まれます。
  3. 上記で渡されたすべてのパラメーターと、値が「_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 の範囲に収まらない場合のみです。

4

3 に答える 3

41

最初に params 辞書を utf-8 に変換してみてください... urlencode は unicode よりもそれを好むようです:

params = urllib.urlencode(dict([k, v.encode('utf-8')] for k, v in params.items()))

もちろん、これは入力がユニコードであることを前提としています。入力が Unicode 以外の場合は、最初に Unicode にデコードしてからエンコードする必要があります。

params['foo'] = my_raw_input.decode('iso-8859-1')
params = urllib.urlencode(dict([k, v.encode('utf-8')] for k, v in params.items()))
于 2009-04-25T01:45:55.883 に答える
6

にエンコードする代わりにutf-8、ペイパルが投稿に使用しているものにエンコードする必要があります。これは、paypal が送信するフォームのキー「charset」の下で利用できます。

だから、次のコードは私のために働いた:

data = dict([(k, v.encode(data['charset'])) for k, v in data.items()])

于 2010-02-08T09:03:21.390 に答える
3

ここで声をかけるのが少し遅いことはわかっていますが、私が見つけた最善の解決策は、彼らが返したものを解析することさえしないことでした. django (何を使用しているのかわかりません) では、彼らが送信した生のリクエストを取得でき、それを逐語的に返しました。次に、cmdキーをそれに置くだけの問題でした。

この方法では、彼らが送信するエンコーディングが問題になることはありません。あなたはそれをすぐに送り返すだけです。

于 2010-07-19T16:34:28.787 に答える