| You are here: Inicio > Inmersión en Python > Servicios Web HTTP > Tratamiento de Last-Modified y ETag | << >> | ||||
Inmersión en PythonPython de novato a experto |
|||||
Ahora que sabe cómo añadir cabeceras HTTP personalizadas a la consulta al servicio web, veamos cómo añadir la funcionalidad de las cabeceras Last-Modified y ETag.
Estos ejemplos muestran la salida con la depuración inactiva. Si sigue teniéndola activa tras la sección anterior puede desactivarla haciendo httplib.HTTPConnection.debuglevel = 0. O simplemente puede dejarla activa, si le apetece.
>>> import urllib2 >>> request = urllib2.Request('http://diveintomark.org/xml/atom.xml') >>> opener = urllib2.build_opener() >>> firstdatastream = opener.open(request) >>> firstdatastream.headers.dict{'date': 'Thu, 15 Apr 2004 20:42:41 GMT', 'server': 'Apache/2.0.49 (Debian GNU/Linux)', 'content-type': 'application/atom+xml', 'last-modified': 'Thu, 15 Apr 2004 19:45:21 GMT', 'etag': '"e842a-3e53-55d97640"', 'content-length': '15955', 'accept-ranges': 'bytes', 'connection': 'close'} >>> request.add_header('If-Modified-Since', ... firstdatastream.headers.get('Last-Modified'))
>>> seconddatastream = opener.open(request)
Traceback (most recent call last): File "<stdin>", line 1, in ? File "c:\python23\lib\urllib2.py", line 326, in open '_open', req) File "c:\python23\lib\urllib2.py", line 306, in _call_chain result = func(*args) File "c:\python23\lib\urllib2.py", line 901, in http_open return self.do_open(httplib.HTTP, req) File "c:\python23\lib\urllib2.py", line 895, in do_open return self.parent.error('http', req, fp, code, msg, hdrs) File "c:\python23\lib\urllib2.py", line 352, in error return self._call_chain(*args) File "c:\python23\lib\urllib2.py", line 306, in _call_chain result = func(*args) File "c:\python23\lib\urllib2.py", line 412, in http_error_default raise HTTPError(req.get_full_url(), code, msg, hdrs, fp) urllib2.HTTPError: HTTP Error 304: Not Modified
| ¿Recuerda todas aquellas cabeceras HTTP que vio impresas cuando activó la depuración? Así es como puede obtener acceso de forma programática a ellas: firstdatastream.headers es un objeto que actúa como un diccionario y le permite obtener cualquiera de las cabeceras individuales devueltas por el servidor HTTP. | |
| En la segunda consulta añadimos la cabecera If-Modified-Since con la última fecha de modificación que nos dio la primera petición. Si los datos no han cambiado, el servidor debería devolver un código de estado 304. | |
| Pues bien, los datos no han cambiado. Puede ver por la traza de depuración que urllib2 lanza una excepción especial, HTTPError, en respuesta del código de estado 304. Esto es un poco inusual y no ayuda demasiado. Después de todo no es un error; le indicamos específicamente al servidor que no nos enviase datos si no habían cambiado, y los datos no cambiaron así que el servidor nos dijo que no nos iba a enviar datos. Eso no es un error; es exactamente lo que esperábamos. |
urllib2 también lanza una excepción HTTPError por condiciones en las que sí pensaríamos como errores, tales como 404 (página no encontrada). De hecho, lanzará HTTPError por cualquier código de estado diferente a 200 (OK), 301 (redirección permanente), o 302 (redirección temporal). Sería más útil a nuestros propósitos capturar el código de estado y devolverlo, simplemente, sin lanzar excepción. Para hacerlo necesitaremos definir un manipulador de URL personalizado.
Este manipulador de URL es parte de openanything.py.
class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):def http_error_default(self, req, fp, code, msg, headers):
result = urllib2.HTTPError( req.get_full_url(), code, msg, headers, fp) result.status = code
return result
| urllib2 está diseñada sobre manipuladores de URL. Cada manipulador es una clase que puede definir cualquier cantidad de métodos. Cuando sucede algo (como un error de HTTP o incluso un código 304) urllib2 hace introspección en la lista de manipuladores definidos a la busca de un método que lo maneje. Usamos una introspección similar en Capítulo 9, Procesamiento de XML para definir manipuladores para diferentes tipos de nodo, pero urllib2 es más flexible e inspecciona todos los manipuladores que se hayan definido para la consulta actual. | |
| urllib2 busca entre los manipuladores definidos y llama a http_error_default cuando encuentra que el servidor le envía un código de estado 304. Definiendo un manipulador personalizado podemos evitar que urllib2 lance una excepción. En su lugar, creamos el objeto HTTPError pero lo devolvemos en lugar de lanzar una excepción con él. | |
| Ésta es la parte clave: antes de volver se ha de guardar el código de estado que devolvió el servidor HTTP. Esto nos permite acceder fácilmente a él desde el programa que llama. |
>>> request.headers{'If-modified-since': 'Thu, 15 Apr 2004 19:45:21 GMT'} >>> import openanything >>> opener = urllib2.build_opener( ... openanything.DefaultErrorHandler())
>>> seconddatastream = opener.open(request) >>> seconddatastream.status
304 >>> seconddatastream.read()
''
El tratamiento de ETag funciona de la misma manera, pero en lugar de buscar Last-Modified y enviar If-Modified-Since, buscamos ETag y enviamos If-None-Match. Empecemos una sesión nueva del IDE.
>>> import urllib2, openanything >>> request = urllib2.Request('http://diveintomark.org/xml/atom.xml') >>> opener = urllib2.build_opener( ... openanything.DefaultErrorHandler()) >>> firstdatastream = opener.open(request) >>> firstdatastream.headers.get('ETag')'"e842a-3e53-55d97640"' >>> firstdata = firstdatastream.read() >>> print firstdata
<?xml version="1.0" encoding="iso-8859-1"?> <feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en"> <title mode="escaped">dive into mark</title> <link rel="alternate" type="text/html" href="http://diveintomark.org/"/> <-- rest of feed omitted for brevity --> >>> request.add_header('If-None-Match', ... firstdatastream.headers.get('ETag'))
>>> seconddatastream = opener.open(request) >>> seconddatastream.status
304 >>> seconddatastream.read()
''
| En estos ejemplos el servidor HTTP ha respondido tanto a la cabecera Last-Modified como a ETag, pero no todos los servidores lo hacen. Como cliente de un servicio web debería estar preparado para usar ambos, pero debe programar de forma defensiva por si se da el caso de que el servidor sólo trabaje con uno de ellos, o con ninguno. | |
<< Establecer el User-Agent |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
Manejo de redirecciones >> |