【问题标题】:Python interface to PayPal - urllib.urlencode non-ASCII characters failingPayPal 的 Python 接口 - urllib.urlencode 非 ASCII 字符失败
【发布时间】:2010-10-21 17:41:16
【问题描述】:

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

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

当我尝试 urllib.urlencode PayPal 发送给我的参数时,我得到一个:

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 字符进行编码以发布到 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 范围时,才会出现问题。

【问题讨论】:

    标签: python unicode paypal urllib2 urllib


    【解决方案1】:

    先尝试将 params 字典转换为 utf-8... urlencode 似乎比 unicode 更喜欢这个:

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

    当然,这假设您的输入是 unicode。如果您的输入不是 unicode,您需要先将其解码为 un​​icode,然后对其进行编码:

    params['foo'] = my_raw_input.decode('iso-8859-1')
    params = urllib.urlencode(dict([k, v.encode('utf-8')] for k, v in params.items()))
    

    【讨论】:

    • 你是对的——这确实消除了 URLEncode 上的异常。但是,现在 PayPal 给了我一个无效的回复。他们是如此痛苦......
    • 所以 krys,如果不是 utf-8,他们(paypal)会记录他们想要的编码吗?
    • 谢谢!小错误:在您给出的第一个示例末尾有一个 ] 太多。
    • 感谢您的出色回答。它确实帮助我解决了我在使用 PayPal IPN 时遇到的问题——但在我的情况下,还有两个问题让我有一段时间感到困惑。 (1) 需要告诉 PayPal 使用 UTF-8 传输。这可以通过输入 PayPal->Profile->My Selling Tools->PayPal 按钮语言编码->More Options->UTF-8 来完成。 (2) 另外,值得指出的是,在沙盒中,选择UTF-8编码没有任何效果(它继续使用其他一些编码),但这在生产环境中有效。
    • 非常感谢您发布您的解决方案,这也适用于 django satchmo,适用于任何可能遇到问题的人。
    【解决方案2】:

    不应编码为utf-8,而应编码为贝宝用于帖子的任何内容。 它在 paypal 发送的表单中的“charset”键下可用。

    所以下面的代码对我有用:

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

    【讨论】:

      【解决方案3】:

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

      这样,他们发送给您的编码无关紧要,您只需将其发送回来。

      【讨论】:

      • 您是否尝试过使用包含 ñ、á、é 等 unicode 字符的 IPN 响应?问题只发生在这些类型的字符上。
      猜你喜欢
      • 2018-04-08
      • 2013-06-04
      • 1970-01-01
      • 2015-08-30
      • 2012-01-02
      • 2016-06-13
      • 2014-12-06
      • 2019-04-06
      • 2013-12-22
      相关资源
      最近更新 更多