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

发布于 2024-07-18 15:55:56 字数 1956 浏览 7 评论 0原文

我正在尝试实现 PayPal IPN 功能。 基本协议是这样的:

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

当我尝试对 PayPal 发送给我的参数进行 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 字符。 这是可以理解的。 我的问题是,如何使用 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 范围时,才会出现问题。

I am trying to implement PayPal IPN functionality. The basic protocol is as such:

  1. The client is redirected from my site to PayPal's site to complete payment. He logs into his account, authorizes payment.
  2. PayPal calls a page on my server passing in details as POST. Details include a person's name, address, and payment info etc.
  3. I need to call a URL on PayPal's site internally from my processing page passing back all the params that were passed in abovem and an additional one called 'cmd' with a value of '_notify-validate'.

When I try to urllib.urlencode the params which PayPal has sent to me, I get a:

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)

I understand that urlencode does ASCII encoding, and in certain cases, a user's contact info can contain non-ASCII characters. This is understandable. My question is, how do I encode non-ASCII characters for POSTing to a URL using urllib2.urlopen(req) (or other method)

Details:

I read the params in PayPal's original request as follows (the GET is for testing):

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()  

The code I use for sending back the request to PayPal from the processing page is:

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

Obviously, the problem only arises if someone's name or address or other field used for the PayPal payment does not fall into the ASCII range.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赢得她心 2024-07-25 15:55:56

首先尝试将 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()))

Try converting the params dictionary to utf-8 first... urlencode seems to like that better than unicode:

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

Of course, this assumes your input is unicode. If your input is something other than unicode, you'll want to decode it to unicode first, then encode it:

params['foo'] = my_raw_input.decode('iso-8859-1')
params = urllib.urlencode(dict([k, v.encode('utf-8')] for k, v in params.items()))
追星践月 2024-07-25 15:55:56

不应编码为 utf-8,而应编码为 PayPal 在帖子中使用的内容。
它可以在 paypal 发送的表单中的关键“字符集”下找到。

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

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

Instead of encoding to utf-8, one should encode to what ever the paypal is using for the post.
It is available under key 'charset' in the form paypal sends.

So the following code worked for me:

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

韵柒 2024-07-25 15:55:56

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

这样,他们发送给您什么编码就不再重要,您只需将其发送回来即可。

I know it's a bit late to chime in here, but the best solution I found was to not even parse what they were giving back. In django (don't know what you're using) I was able to get the raw request they sent, which I passed back verbatim. Then it was just a matter of putting the cmd key onto that.

This way it never matters what encoding they send you, you're just sending it right back.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文