Интерфейс Python для PayPal - сбой не-ASCII символов urllib.urlencode - PullRequest
20 голосов
/ 25 апреля 2009

Я пытаюсь реализовать функциональность PayPal IPN. Основной протокол таков:

  1. Клиент перенаправляется с моего сайта на сайт PayPal для завершения платежа. Он входит в свой аккаунт, авторизует оплату.
  2. PayPal вызывает страницу на моем сервере с подробным описанием POST. Подробная информация включает имя человека, адрес, информацию об оплате и т. Д.
  3. Мне нужно вызвать внутренний URL-адрес на сайте PayPal со страницы обработки, передавая все параметры, которые были переданы выше, и дополнительный параметр с именем «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 символы. Это понятно. У меня вопрос, как мне кодировать не-ASCII символы для POSTing в URL, используя urllib2.urlopen (req) (или другой метод)

подробности:

Я прочитал параметры в исходном запросе 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.

Ответы [ 3 ]

41 голосов
/ 25 апреля 2009

Попробуйте сначала преобразовать словарь параметров в 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()))
6 голосов
/ 08 февраля 2010

Вместо кодирования в utf-8 следует кодировать то, что когда-либо PayPal использует для поста. Он доступен в разделе «кодировка» в форме, которую отправляет PayPal.

Так что следующий код работал для меня:

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

3 голосов
/ 19 июля 2010

Я знаю, что здесь уже поздно звонить, но лучшим решением, которое я нашел, было даже не анализировать то, что они возвращали. В django (не знаю, что вы используете) я смог получить необработанный запрос, который они отправили, и я дословно передал. Тогда нужно было просто вставить ключ cmd.

Таким образом, не имеет значения, какую кодировку вам отправляют, вы просто отправляете это обратно.

...