PayPal的Python接口 - urllib.urlencode非ASCII字符失败

时间:2009-04-25 00:24:09

标签: python unicode paypal urllib2 urllib

我正在尝试实现PayPal IPN功能。基本协议如下:

  1. 客户端从我的网站重定向到PayPal的网站以完成付款。他登录到他的帐户,授权付款。
  2. PayPal在我的服务器上调用一个页面,将详细信息作为POST传递。详细信息包括人员姓名,地址和付款信息等。
  3. 我需要从我的处理页面内部调用PayPal网站上的URL,传回上面传递的所有参数以及另一个名为'cmd'的值为'_notify-validate'的参数。
  4. 当我尝试urllib.urlencode PayPal寄给我的params时,我得到了:

    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)(或其他方法)将非ASCII字符编码为POST到URL

    详细信息:

    我在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范围时,才会出现问题。

3 个答案:

答案 0 :(得分: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()))

答案 1 :(得分:6)

不应该编码为utf-8,而应编码到PayPal用于帖子的内容。 它以paypal发送形式在关键'charset'下提供。

所以以下代码对我有用:

  

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

答案 2 :(得分:3)

我知道这里有点迟到,但我找到的最佳解决方案是甚至不解析他们所回馈的内容。在django(不知道你在使用什么)我能够得到他们发送的原始请求,我逐字传回。然后只需要将cmd键放在上面。

这样,它们发送给你的编码永远不会重要,你只需将它发回去。