导航:起始页 > Dive Into Python > HTTP Web 服务 > 处理 Last-Modified 和 ETag | << >> | ||||
深入 Python :Dive Into Python 中文版Python 从新手到专家 [Dip_5.4b_CPyUG_Release] |
既然你知道如何在你的 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 是一个类似 dictionary 行为的对象并且允许你获得任何个别的从 HTTP 服务器返回的头信息。 | |
在第二次请求时,你用第一次请求获得的最近修改时间添加了 If-Modified-Since 头信息。如果数据没被改变,服务器应该返回一个 304 状态代码。 | |
毫无疑问,数据没被改变。你可以从跟踪返回结果看到 urllib2 抛出了一个特殊异常,HTTPError,以响应 304 状态代码。这有点不寻常,并且完全没有任何帮助。毕竟,它不是个错误;你明确地询问服务器如果没有变化就不要发送任何数据,并且数据没有变化,所以服务器告诉你它没有为你发送任何数据。那不是个错误;实际上也正是你所期望的。 |
urllib2 也为你认为是错误的其他条件引发 HTTPError 异常,比如 404 (page not found)。实际上,它将为任何 除了状态代码 200 (OK)、301 (permanent redirect)或 302 (temporary redirect) 之外的状态引发 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 是很灵活的,还可以内省为当前请求所定义的所有处理器。 | |
当从服务器接收到一个 304 状态代码时,urllib2 查找定义的操作并调用 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 | |
处理重定向 >> |