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

Kry*_*ski 20 python unicode paypal urllib urllib2

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

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

当我尝试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)
Run Code Online (Sandbox Code Playgroud)

我知道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()  
Run Code Online (Sandbox Code Playgroud)

我用来从处理页面向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
Run Code Online (Sandbox Code Playgroud)

显然,只有当某人的姓名或地址或用于PayPal付款的其他字段不属于ASCII范围时,才会出现问题.

Jar*_*die 41

尝试首先将params字典转换为utf-8 ... urlencode似乎比unicode更好:

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

当然,这假设您的输入是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()))
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的回答.这真的帮助我解决了我在PayPal IPN上遇到的问题 - 但是在我的情况下还有两个问题让我吵了一阵.(1)有必要告诉PayPal使用UTF-8进行传输.这可以通过输入PayPal-> Profile-> My Selling Tools-> PayPal按钮语言编码 - >更多选项 - > UTF-8来完成.(2)此外,值得指出的是,在Sandbox中,选择UTF-8编码没有任何影响(它继续使用其他编码),但这在生产环境中有效. (3认同)

小智 6

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

所以以下代码对我有用:

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