2009-04-25 16 views
20

我試圖實現PayPal IPN功能。基本協議是這樣的:PayPal的Python接口 - urllib.urlencode非ASCII字符失敗

  1. 客戶端從我的網站重定向到PayPal的網站完成付款。他登錄到他的帳戶,授權付款。
  2. PayPal在我的服務器上調用一個頁面,作爲POST傳遞詳細信息。詳細信息包括一個人的姓名,地址和付款信息等。
  3. 我需要在PayPal網站上從我的處理頁面內部調用一個網址,以傳回上面傳入的所有參數以及另一個名爲'cmd'的參數'_notify-validate'的值。

當我嘗試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字符。這是可以理解的。我的問題是,我怎麼編碼非ASCII字符使用urllib2.urlopen(REQ)(或其他方式)

詳細信息張貼到一個URL:

我讀PayPal的原始請求的PARAMS如下(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範圍時纔會出現問題。

回答

41

嘗試PARAMS字典轉換爲UTF-8第一...進行urlencode似乎喜歡比Unicode的更好:

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

當然,這裏假設你的輸入是unicode。如果輸入是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())) 
+0

你是對的 - 這確實擺脫了URLEncode上的異常。但是,現在PayPal給了我一個無效的答覆。他們是如此痛苦... – 2009-04-25 02:08:34

+1

所以krys,他們(貝寶)文件他們想要什麼編碼,如果它不是utf-8? – 2009-04-26 19:24:05

6

而是編碼utf-8的,應該編碼爲什麼都PayPal是使用後。 它在PayPal發送的關鍵字'charset'下可用。

所以下面的代碼爲我工作:

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

3

我知道這是一個有點晚在這裏附和,但我找到了最好的解決辦法是,即使不能解析它們是什麼回饋。在django(不知道你在用什麼)我能夠得到他們發送的原始請求,我逐字回傳。然後它只是把cmd鍵放到那裏。

這種方式永遠不會影響他們發送給你的編碼,你只是馬上發送它。