我正在尝试实现PayPal IPN功能,基本协议如下:
- 客户从我的网站重定向到PayPal的网站以完成付款。他登录自己的帐户,授权付款。
- PayPal调用我的服务器上的一个页面,通过POST方式传递详细信息。详细信息包括个人姓名、地址和付款信息等。
- 我需要从我的处理页面内部调用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字符进行编码以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范围时,才会出现问题。