Requests: UnicodeEncodeError : le codec 'latin-1' ne peut pas encoder les caractères

Créé le 20 déc. 2013  ·  7Commentaires  ·  Source: psf/requests

Demandes est la dernière version.
Lorsque j'essaie de publier les données contenant des caractères chinois, cette exception est levée.

Traceback (most recent call last):
  File "X/threading.py", line 639, in _bootstrap_inner
  File "X/threading.py", line 596, in run
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\salesforce\api.py", line 546, in execute_anonymous
    headers=headers)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\api.py", line 88, in post
    return request('post', url, data=data, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\sessions.py", line 338, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\sessions.py", line 441, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\adapters.py", line 292, in send
    timeout=timeout
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\packages\urllib3\connectionpool.py", line 428, in urlopen
    body=body, headers=headers)
  File "C:\Users\Administrator\Dropbox\Sublime3056\Data\Packages\SublimeApex\requests\packages\urllib3\connectionpool.py", line 280, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "X/http/client.py", line 1049, in request
  File "X/http/client.py", line 1086, in _send_request
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 1632-1633: ordinal not in range(256)

Commentaire le plus utile

Donc, ST 3, mais pas la révision la plus récente. Ok, ça nous donne quelque chose. Plus précisément, Sublime Text 3 utilise Python 3.3, et non Python 2.7 (que Sublime Text 2 utilisait). Cela signifie que toutes les chaînes par défaut dans Sublime Apex sont des chaînes unicode.

Si vous ouvrez le fichier Python 3.3 http.client , vous constaterez que la fonction _send_request() ressemble à ceci :

# Honor explicitly requested Host: and Accept-Encoding: headers.
header_names = dict.fromkeys([k.lower() for k in headers])
skips = {}
if 'host' in header_names:
    skips['skip_host'] = 1
if 'accept-encoding' in header_names:
    skips['skip_accept_encoding'] = 1

self.putrequest(method, url, **skips)

if body is not None and ('content-length' not in header_names):
    self._set_content_length(body)
for hdr, value in headers.items():
    self.putheader(hdr, value)
if isinstance(body, str):
    # RFC 2616 Section 3.7.1 says that text default has a
    # default charset of iso-8859-1.
    body = body.encode('iso-8859-1')
self.endheaders(body)

Maintenant, ISO-8859-1 est un alias pour Latin-1, qui est le codec avec lequel nous avons des problèmes. Le problème que nous avons est que Sublime Apex fournit un corps de chaîne unicode aux requêtes, que httplib doit encoder en octets. Prenant la valeur par défaut de la RFC 2616, il conclut que vous voulez Latin-1, qui n'inclut aucun caractère chinois. De toute évidence, l'encodage échoue et vous obtenez l'exception en question.

Considérant que Sublime Apex prétend dans les en-têtes qu'il envoie envoyer des données encodées en UTF-8 (ce qui est actuellement un mensonge), Sublime Apex veut encoder les données en UTF-8 avant de les envoyer. Cela signifie que toute ligne envoyant des données (dans ce cas, la ligne 545 de salesforce/api.py ) doit se lire comme ceci :

response = requests.post(self.apex_url, soap_body.encode('utf-8'), verify=False, headers=headers)

Pour le bien de tous ceux qui souhaitent confirmer mon diagnostic, voici un petit exemple de code qui confirme le problème :

a = "\u13E0\u19E0\u1320"
a.encode('latin1')  # Throws UnicodeEncodeError, proves that this can't be expressed in ISO-8859-1.
a.encode('utf-8')  # Totally fine.
r = requests.post('http://httpbin.org/post', data=a)  # Using unicode string, throws UnicodeEncodeError blaming Latin1.
r = requests.post('http://httpbin.org/post', data=a.encode('utf-8'))  # Works fine.

Merci d'avoir soulevé cette question avec nous, mais ce n'est pas un bogue de requêtes. =)

Tous les 7 commentaires

Fichier "X/http/client.py"

Avez-vous écrit X parce que c'est un chemin vers un fichier local ? Si c'est le cas, votre structure de répertoire peut prêter à confusion pour urllib3. Si ce n'est pas le cas, vous devriez probablement le signaler sur bugs.python.org car ce n'est pas quelque chose que je pense que les demandes devraient traiter. Cela semble passer de httplib (ou http sur Python 3 que je suppose que vous utilisez).

@sigmavirus24 ,

J'ai utilisé des requêtes dans le plugin sublime, si le soap_body dans la déclaration ci-dessous ne contient aucun caractère chinois, il n'y aura pas d'exception.

response = requests.post(self.apex_url, soap_body, verify=False, headers=headers)

Premièrement, à moins que vous n'utilisiez une version de Sublime Apex différente de celle de leur référentiel public, Requests n'est _pas_ la dernière version, c'est la version 1.2.3. Pouvez-vous me dire quelle version de Sublime Text vous utilisez ?

C'est sublime texte 3056

Donc, ST 3, mais pas la révision la plus récente. Ok, ça nous donne quelque chose. Plus précisément, Sublime Text 3 utilise Python 3.3, et non Python 2.7 (que Sublime Text 2 utilisait). Cela signifie que toutes les chaînes par défaut dans Sublime Apex sont des chaînes unicode.

Si vous ouvrez le fichier Python 3.3 http.client , vous constaterez que la fonction _send_request() ressemble à ceci :

# Honor explicitly requested Host: and Accept-Encoding: headers.
header_names = dict.fromkeys([k.lower() for k in headers])
skips = {}
if 'host' in header_names:
    skips['skip_host'] = 1
if 'accept-encoding' in header_names:
    skips['skip_accept_encoding'] = 1

self.putrequest(method, url, **skips)

if body is not None and ('content-length' not in header_names):
    self._set_content_length(body)
for hdr, value in headers.items():
    self.putheader(hdr, value)
if isinstance(body, str):
    # RFC 2616 Section 3.7.1 says that text default has a
    # default charset of iso-8859-1.
    body = body.encode('iso-8859-1')
self.endheaders(body)

Maintenant, ISO-8859-1 est un alias pour Latin-1, qui est le codec avec lequel nous avons des problèmes. Le problème que nous avons est que Sublime Apex fournit un corps de chaîne unicode aux requêtes, que httplib doit encoder en octets. Prenant la valeur par défaut de la RFC 2616, il conclut que vous voulez Latin-1, qui n'inclut aucun caractère chinois. De toute évidence, l'encodage échoue et vous obtenez l'exception en question.

Considérant que Sublime Apex prétend dans les en-têtes qu'il envoie envoyer des données encodées en UTF-8 (ce qui est actuellement un mensonge), Sublime Apex veut encoder les données en UTF-8 avant de les envoyer. Cela signifie que toute ligne envoyant des données (dans ce cas, la ligne 545 de salesforce/api.py ) doit se lire comme ceci :

response = requests.post(self.apex_url, soap_body.encode('utf-8'), verify=False, headers=headers)

Pour le bien de tous ceux qui souhaitent confirmer mon diagnostic, voici un petit exemple de code qui confirme le problème :

a = "\u13E0\u19E0\u1320"
a.encode('latin1')  # Throws UnicodeEncodeError, proves that this can't be expressed in ISO-8859-1.
a.encode('utf-8')  # Totally fine.
r = requests.post('http://httpbin.org/post', data=a)  # Using unicode string, throws UnicodeEncodeError blaming Latin1.
r = requests.post('http://httpbin.org/post', data=a.encode('utf-8'))  # Works fine.

Merci d'avoir soulevé cette question avec nous, mais ce n'est pas un bogue de requêtes. =)

Merci.

r = request.post(' http://httpbin.org/post ', data=a.encode('utf-8'))
très utile,
Merci!

Cette page vous a été utile?
0 / 5 - 0 notes