您在这里:首页 > 深入 Python > HTTP Web 服务 > 处理 Last-Modified 和 ETag | << >> | ||||
深入 Python从 Python 新手到专家 |
既然您已经知道如何向 Web 服务请求添加自定义 HTTP 头部,让我们来看看如何添加对 Last-Modified 和 ETag 头部的支持。
这些示例显示了关闭调试后的输出。如果您在上一节中仍然打开了调试,则可以通过设置 httplib.HTTPConnection.debuglevel = 0 来将其关闭。或者,如果这对您有帮助,您可以保持调试打开状态。
>>> 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
![]() |
还记得您在打开调试时看到打印出来的所有 HTTP 头部吗?这就是您以编程方式访问它们的方式:firstdatastream.headers 是一个 行为类似于字典的对象,它允许您获取从 HTTP 服务器返回的任何单个头部。 |
![]() |
在第二个请求中,您添加了 If-Modified-Since 头部,其中包含第一个请求中的最后修改日期。如果数据没有更改,服务器应该返回 304 状态码。 |
![]() |
果然,数据没有改变。您可以从回溯中看到,urllib2 针对 304 状态码抛出了一个特殊的异常,即 HTTPError。这有点不寻常,而且不是很有帮助。毕竟,这不是一个错误;您明确要求服务器在数据没有更改的情况下不要向您发送任何数据,而数据没有更改,所以服务器告诉您它没有向您发送任何数据。这不是错误;这正是您所希望的。 |
urllib2 还会针对您认为是错误的情况引发 HTTPError 异常,例如 404(未找到页面)。事实上,对于除 200(OK)、301(永久重定向)或 302(临时重定向)之外的 任何 状态码,它都会引发 HTTPError。捕获状态码并简单地返回它,而不抛出异常,这对您的目的更有帮助。为此,您需要定义一个自定义 URL 处理程序。
这个自定义 URL 处理程序是 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 是围绕 URL 处理程序设计的。每个处理程序只是一个可以定义任意数量方法的类。当发生某些事情时(例如 HTTP 错误,甚至 304 代码),urllib2 会反省已定义的处理程序列表,以查找可以处理它的方法。您在 第 9 章,XML 处理 中使用了类似的反省来为不同的节点类型定义处理程序,但 urllib2 更灵活,它会反省为当前请求定义的尽可能多的处理程序。 |
![]() |
当 urllib2 从服务器遇到 304 状态码时,它会在已定义的处理程序中搜索并调用 http_error_default 方法。通过定义自定义错误处理程序,您可以防止 urllib2 抛出异常。相反,您创建了 HTTPError 对象,但返回它而不是抛出它。 |
![]() |
这是关键部分:在返回之前,您保存了 HTTP 服务器返回的状态码。这将允许您从调用程序轻松访问它。 |
>>> 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()
''
处理 ETag 的方式大致相同,但不是检查 Last-Modified 并发送 If-Modified-Since,而是检查 ETag 并发送 If-None-Match。让我们从一个全新的 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()
''
![]() |
|
在这些示例中,HTTP 服务器同时支持 Last-Modified 和 ETag 头部,但并非所有服务器都支持。作为 Web 服务客户端,您应该准备好同时支持两者,但您必须进行防御性编码,以防服务器只支持其中之一或两者都不支持。 |
<< 设置 User-Agent |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
处理重定向 >> |