2009-04-25 4 views
20

Je suis en train de mettre en œuvre la fonctionnalité PayPal IPN. Le protocole de base est en tant que tel:Interface Python à PayPal - urllib.urlencode caractères non-ASCII défaut

  1. Le client est redirigé depuis mon site vers le site PayPal pour effectuer le paiement. Il se connecte à son compte, autorise le paiement.
  2. PayPal appelle une page sur mon serveur en passant en mode POST. Les détails incluent repassant tous les params qui ont été adoptées dans abovem et un supplémentaire appelé nom, adresse et informations de paiement, etc.
  3. d'une personne que je dois appeler une URL sur le site de PayPal interne de ma page de traitement « cmd » avec valeur de '_notify-validate'.

Lorsque je tente de urllib.urlencode les params que PayPal a envoyé à moi, je reçois:

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) 

Je comprends que urlencode-t codage ASCII, et dans certains cas, les coordonnées d'un utilisateur peut contenir des caractères non-ASCII. C'est compréhensible. Ma question est, comment puis-je encoder des caractères non-ASCII pour une mise en ligne sur l'URL en utilisant urllib2.urlopen (REQ) (ou autre méthode)

Détails:

je lis les params dans la demande initiale de PayPal suit (l'EEG pour le test):

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

le code que j'utilise pour renvoyer la demande à PayPal depuis la page de traitement est:

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 

Évidemment, le problème ne se pose que si le nom ou l'adresse de quelqu'un ou tout autre champ utilisé pour le paiement PayPal ne tombe pas dans la plage ASCII.

Répondre

41

Essayez de convertir le dictionnaire params à utf-8 d'abord ... urlencode semble aimer mieux que unicode:

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

Bien sûr, cela suppose que votre entrée est unicode. Si votre entrée est autre chose que unicode, vous aurez envie de le décoder à unicode d'abord, puis l'encoder:

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

Vous aviez raison - ceci s'est débarrassé de l'exception sur URLEncode. Cependant, maintenant PayPal me donne une réponse invalide. Ils sont une telle douleur ... –

+1

donc krys, documentent-ils (paypal) ce qu'ils veulent, si ce n'est pas utf-8? –

+0

Merci! Bug mineur: il y a trop à la fin du premier exampe que vous donnez. –

6

lieu de codage utf-8, il faut encoder à ce que jamais le paypal utilise pour le poste . Il est disponible sous la clé 'charset' sous la forme paypal envoie.

Ainsi, le code suivant a fonctionné pour moi:

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

3

Je sais qu'il est un peu tard pour sonner ici, mais la meilleure solution que j'ai trouvé à même pas analysé ce qu'ils étaient redonner. En django (je ne sais pas ce que vous utilisez), j'ai été en mesure d'obtenir la requête brute qu'ils ont envoyée, que j'ai renvoyée mot pour mot. Ensuite, c'était juste une question de mettre la touche cmd sur ça.

De cette façon, il importe jamais ce que l'encodage qu'ils vous envoient, vous êtes juste envoyer retour.

+0

Avez-vous essayé ceci avec une réponse IPN qui inclut des caractères Unicode tels que ñ, á, é, etc.? Le problème se produit uniquement avec ces types de caractères. –