您当前位置:首页 > 深入 Python > HTTP Web 服务 > HTTP 的特性 | << >> | ||||
深入 Python从 Python 新手到专家 |
HTTP 有五个重要特性,您应该支持它们。
User-Agent 只是客户端在请求网页、联合供稿或任何类型的 HTTP Web 服务时,向服务器表明其身份的一种方式。当客户端请求资源时,它应该始终尽可能具体地表明自己的身份。这使得服务器端管理员能够在出现任何重大错误时与客户端开发人员取得联系。
默认情况下,Python 会发送一个通用的 User-Agent:Python-urllib/1.15。在下一节中,您将看到如何将其更改为更具体的标识。
有时资源会移动。网站会被重新组织,页面会移动到新的地址。甚至 Web 服务也可以重新组织。位于 http://example.com/index.xml 的联合供稿可能会移动到 http://example.com/xml/atom.xml。或者,随着组织的扩展和重组,整个域可能会移动;例如,http://www.example.com/index.xml 可能会被重定向到 http://server-farm-1.example.com/index.xml。
每次您从 HTTP 服务器请求任何类型的资源时,服务器都会在其响应中包含一个状态码。状态码 200 表示“一切正常,这是您请求的页面”。状态码 404 表示“找不到页面”。(您可能在浏览网页时看到过 404 错误。)
HTTP 有两种不同的方式来表示资源已移动。状态码 302 是临时重定向;它表示“哎呀,它被临时移动到这里了”(然后在 Location: 标头中给出临时地址)。状态码 301 是永久重定向;它表示“哎呀,它被永久移动了”(然后在 Location: 标头中给出新地址)。如果您收到 302 状态码和一个新地址,HTTP 规范规定您应该使用新地址来获取您请求的内容,但是下次您想要访问相同的资源时,您应该重试旧地址。但是,如果您收到 301 状态码和一个新地址,您应该从那时起就使用新地址。
urllib.urlopen 会在从 HTTP 服务器接收到相应的代码时自动“跟随”重定向,但不幸的是,它不会告诉您它是什么时候这样做的。您最终会得到您请求的数据,但您永远不会知道底层库“好心地”为您进行了重定向。因此,您将继续访问旧地址,并且每次都会被重定向到新地址。这是两次往返而不是一次:效率不高!在本章的后面,您将看到如何解决这个问题,以便您可以正确有效地处理永久重定向。
有些数据一直在变化。CNN.com 的主页每隔几分钟就会不断更新。另一方面,Google.com 的主页每隔几周才会更改一次(当他们发布特殊的节日徽标或宣传新服务时)。Web 服务也不例外;通常服务器知道您请求的数据上次更改的时间,并且 HTTP 提供了一种方法,让服务器将此上次修改日期与您请求的数据一起包含在内。
如果您第二次(或第三次、第四次)请求相同的数据,您可以告诉服务器您上次获得的上次修改日期:您在请求中发送一个 If-Modified-Since 标头,其中包含您上次从服务器获得的日期。如果数据自那时以来没有改变,服务器会返回一个特殊的 HTTP 状态码 304,这意味着“自您上次请求以来,此数据没有改变”。为什么这是一个改进?因为当服务器发送 304 时,它不会重新发送数据。您收到的只是状态码。因此,如果数据没有改变,您就不需要一遍又一遍地下载相同的数据;服务器假定您在本地缓存了数据。
所有现代 Web 浏览器都支持上次修改日期检查。如果您曾经访问过一个页面,并在一天后再次访问同一个页面,发现它没有改变,并且想知道为什么它第二次加载得如此之快——这可能就是原因。您的 Web 浏览器在第一次访问时将页面的内容缓存到本地,当您第二次访问时,您的浏览器会自动发送它第一次从服务器获得的上次修改日期。服务器只需回复 304: Not Modified,这样您的浏览器就知道从其缓存中加载页面。Web 服务也可以如此智能。
Python 的 URL 库没有对上次修改日期检查的内置支持,但是由于您可以向每个请求添加任意标头并在每个响应中读取任意标头,因此您可以自己添加对它的支持。
ETag 是实现与上次修改日期检查相同目标的另一种方法:不要重新下载没有更改的数据。它的工作原理是,服务器将数据的某种哈希值(在 ETag 标头中)与您请求的数据一起发送。这个哈希值是如何确定的完全取决于服务器。第二次请求相同的数据时,您将在 If-None-Match: 标头中包含 ETag 哈希值,如果数据没有改变,服务器将向您返回 304 状态码。与上次修改日期检查一样,服务器只发送 304;它不会第二次向您发送相同的数据。通过在第二次请求中包含 ETag 哈希值,您是在告诉服务器,如果数据仍然与此哈希值匹配,则无需重新发送相同的数据,因为您仍然拥有上次的数据。
Python 的 URL 库没有对 ETag 的内置支持,但您将在本章后面看到如何添加它。
最后一个重要的 HTTP 特性是 gzip 压缩。当您谈论 HTTP Web 服务时,您几乎总是在谈论通过网络来回传输 XML。XML 是文本,而且是相当冗长的文本,而文本通常可以很好地压缩。当您通过 HTTP 请求资源时,您可以要求服务器如果它有任何新数据要发送给您,请以压缩格式发送。您在请求中包含 Accept-encoding: gzip 标头,如果服务器支持压缩,它将向您返回 gzip 压缩的数据,并使用 Content-encoding: gzip 标头对其进行标记。
Python 的 URL 库本身没有对 gzip 压缩的内置支持,但您可以向请求添加任意标头。并且 Python 附带了一个单独的 gzip 模块,该模块具有一些函数,您可以使用它们自行解压缩数据。
请注意,我们用于下载联合供稿的小型单行脚本不支持任何这些 HTTP 特性。让我们看看如何改进它。
<< 如何不通过 HTTP 获取数据 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
调试 HTTP Web 服务 >> |