代码之家  ›  专栏  ›  技术社区  ›  Krystian Cybulski

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

  •  20
  • Krystian Cybulski  · 技术社区  · 17 年前

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

    1. 客户将从我的网站重定向到PayPal的网站以完成付款。他登录自己的账户,授权付款。
    2. PayPal调用我服务器上的一个页面,以POST方式传递详细信息。详细信息包括一个人的姓名、地址和付款信息等。

    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字符进行编码,以便将POSTing发送到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()  
    

    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 回复  |  直到 17 年前
        1
  •  41
  •   Jarret Hardie    16 年前

    请先尝试将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()))
    
        2
  •  6
  •   Abhijeet Kasurde Arun Binoy    11 年前

    而不是编码到 utf-8 ,人们应该对贝宝在帖子中使用的内容进行编码。 它可以在贝宝发送的表格中的“字符集”下找到。

    因此,以下代码对我有效:

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

        3
  •  3
  •   KFB    16 年前

    我知道在这里插话有点晚了,但我找到的最好的解决方案是甚至不解析他们反馈的内容。在django(不知道你在用什么)中,我能够得到他们发送的原始请求,我逐字传递了回来。然后,只需将cmd键放在上面即可。

    这样一来,他们发送给你的编码就无关紧要了,你只需要直接发送回来。