¿Cómo enviar contenido utf-8 en una solicitud urllib2?

Estoy luchando con la siguiente pregunta durante la última mitad del día y, aunque he encontrado información sobre problemas similares, no hay nada que realmente llame la atención.

Estoy intentando enviar una solicitud PUT usando urllib2 con datos que contienen algunos caracteres Unicode:

body = u'{ "bbb" : "asdf\xd7\xa9\xd7\x93\xd7\x92"}' conn = urllib2.Request(request_url, body, headers) conn.get_method = lambda: 'PUT' response = urllib2.urlopen(conn) 

He intentado usar body = body.encode('utf-8') y otras variaciones, pero haga lo que haga, obtengo el siguiente error:

 UnicodeEncodeError at ... 'ascii' codec can't decode byte 0xc3 in position 15: ordinal not in range(128) 

Con una de las siguientes stacks de llamadas:

 File "..." in ... 195. response = urllib2.urlopen(conn) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in urlopen 126. return _opener.open(url, data, timeout) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in open 394. response = self._open(req, data) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in _open 412. '_open', req) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in _call_chain 372. result = func(*args) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in http_open 1199. return self.do_open(httplib.HTTPConnection, req) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in do_open 1168. h.request(req.get_method(), req.get_selector(), req.data, headers) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in request 955. self._send_request(method, url, body, headers) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in _send_request 989. self.endheaders(body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in endheaders 951. self._send_output(message_body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in _send_output 815. self.send(message_body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in send 787. self.sock.sendall(data) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py" in meth 224. return getattr(self._sock,name)(*args) 

O la siguiente stack de llamadas (para cuando hago body = body.encode('utf-8') ):

 File "..." in ... 195. response = urllib2.urlopen(conn) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in urlopen 126. return _opener.open(url, data, timeout) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in open 394. response = self._open(req, data) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in _open 412. '_open', req) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in _call_chain 372. result = func(*args) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in http_open 1199. return self.do_open(httplib.HTTPConnection, req) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py" in do_open 1168. h.request(req.get_method(), req.get_selector(), req.data, headers) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in request 955. self._send_request(method, url, body, headers) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in _send_request 989. self.endheaders(body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in endheaders 951. self._send_output(message_body) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py" in _send_output 809. msg += message_body 

¿Qué estoy haciendo mal? ¿Cómo puedo enviar un cuerpo con caracteres Unicode a través de urllib2? Si no hay caracteres Unicode, todo funciona bien.

También tenga en cuenta que mi encabezado Content-Type está establecido en application/json;charset=utf-8 .

Si es relevante de alguna manera, el contexto de lo que estoy haciendo es el siguiente: estoy recibiendo una solicitud a mi servidor Django y delego la solicitud a otro servidor Django. No redirecciono, solo envíe la solicitud desde mi propio servidor, obtenga la respuesta y envíela. Entonces el body es el request.body en la vista de Django.

Editar:

Mis encabezados son:

 { 'Origin': 'http://10.0.0.146:8000', 'Accept-Language': 'en-US,en;q=0.8', 'Accept-Encoding': 'gzip,deflate,sdch', 'Host': 'localhost:5000', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Connection': 'keep-alive', 'X-Requested-With': 'XMLHttpRequest', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Referer': 'http://localhost:5000/', 'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'ApiKey ogkLPgSESNyTOgIdbSLDhJjvyVJcbg:0d5897b5204c2f2527f532c6a97ba18a7f06acdc', 'Cookie': 'username=ogkLPgSESNyTOgIdbSLDhJjvyVJcbg; _we_wk_ls_=%7B%22time%22%3A1369123506709%7D; __jwpusr=39e63770-ec5c-4b96-9f7f-b199703d0d36; sessionid=0d741a7560258b301979a1c853b42a81; api_key=0d5897b5204c2f2527f532c6a97ba18a7f06acdc' } 

Necesitas pasar solo cadenas de bytes a la Request . Esto se aplica a los encabezados, la url y el cuerpo.

Si alguna de esas tres entradas contiene valores de Unicode, las conversiones automáticas entre Unicode y las cadenas se realizarán al concatenar, lo que invariablemente llevará al dolor.