DiveIntoPythonZh/2007-08-01

8-1<X11>openanything.xml HTTP web 服务

11.1 概览

  1. Para 2Simply stated, HTTP web services are programmatic ways of sending and receiving data from remote servers using the operations of HTTP directly.
    简单地讲,HTTP web 服务是指直接使用 HTTP 操作从远程服务器按部就班地发送和接收数据。
    (./) 简单地讲,HTTP web 服务是指以编程的方式直接使用 HTTP 操作从远程服务器发送和接收数据。

  2. Para 3The main advantage of this approach is simplicity,...
    利用这种方法的要点简单的,……
    (./) 这种方法的主要优点是简单,……

  3. 例11.1上, Para -2:在后面的几章里,我们将探索使用 HTTP <!> 数据发送和接收传输的 API…… (./) 进行

11.2 避免通过 HTTP 重复地获取数据

11.3 HTTP 特性

  1. 重定向, Para 3:……然后在 Location: 头部给出新地址
    (./) 然后在 Location: 头信息中给出新地址

  2. Last-Modified/If-Modified-Since, Para 1
    通常服务器指导 <!> 你所请求的数据的最后修改时间 (./) 知道

  3. Last-Modified/If-Modified-Since, Para 2
    ……你可以告诉服务器你上一次获得的最后修改日期:在你的请求中发送 {X} 一个 If-Modified-Since 头信息……为什么 {X} 这一点有何进步呢?因为 {X} 当服务器发送状态编码 304 时,不再重新发送数据……

  4. Last-Modified/If-Modified-Since, Para 4
    所有现代的浏览器都支持最近修改 {i} (last-modified)的数据检查。……服务器简单地返回 304: {i} Not Modified( 没有修改

  5. ETag/If-None-Match, Para 1
    ETag 是实现与最近修改数据检查同样的功能的另一种方法:没有变化时不重新下载数据。其工作原理 方式是:服务器发送你所请求的数据的同时,发送某种数据的 hash (在 ETag 头信息中 {i} 给出),hash 的确定完全取决于服务器。当第二次请求相同的数据时, {i} 你需要在 If-None-Match: 头信息中包含 ETag hash,……在第二次请求时,通过包含 ETag hash,你 {X} 告诉服务器……

  6. 压缩, Para 1When you talk about HTTP web services, you're almost always talking about moving XML back and forth over the wire. XML is text, and quite verbose text at that, and text generally compresses well.
    当谈论 HTTP web 服务时,几乎总是会谈及在网络线路上传输的 XML。XML 是文本,而且还是相当冗长的文本,并且文本通常可以被很好地压缩。
    (./) 关于 HTTP web 服务的主题几乎总是会涉及在网络线路上传输的 XML。XML 是文本,而且还是相当冗长的文本,文本通常可以被很好地压缩。

11.4 调试 HTTP web 服务

  1. 例11.3, (1)...you can set the debugging flag on the HTTPConnection class that urllib uses internally to connect to the HTTP server. 你可以为 urllib 使用内部的 HTTPConnection 类设置调试标记来访问 HTTP 服务器
    (./) 你可以为 HTTPConnection 类(urllib 在内部使用它来访问 HTTP 服务器)设置调试标记

  2. 例11.3, (6):服务器也会告诉你响应请求的数据、一些有关服务器自身的信息, {i} 以及传给你的数据的内容类型。

11.5 设置 User-Agent

  1. 例11.4, (1):如果你的 Python IDE 仍旧为上一节的例子而打开着,你可以略过这一步,在开启 HTTP 调试 <!> 你能看到网络线路上的实际传输过程。 (./)

  2. 例11.4, (3):第二步是创建一个 URL 开启器 (opener)。可以使用任何数量的操作者来控制响应的处理。但你也可以创建一个没有任何自定义处理的开启器,这就是这里的操作方式
    (./) 第二步是创建一个 URL 开启器 (opener)。可以接受任何数量的处理器来控制响应的处理。但你也可以创建一个没有任何自定义处理器的开启器,在这儿你就是这么做的

  3. 例11.5 Request 添加头信息 (./) Request 添加头信息

  4. 例11.5, (2)Convention dictates that a User-Agent should be in this specific format: an application name, followed by a slash, followed by a version number.
    User-Agent 的协商指令应该使用如下的特殊格式:应用名,跟一个斜线,跟版本号。
    (./) User-Agent 的约定格式是:应用名,跟一个斜线,跟版本号。

  5. 同上User-Agent 通常要记录经过服务器的连同你的请求的其他详细信息,包含你的应用的 URL,如果发生错误,允许服务器管理员通过查看他们的访问日志与你联系。
    (./) 和你的请求的其他信息一样,User-Agent 会被服务器纪录下来,其中包含你的应用的 URL。如果发生错误,服务器管理员就能通过查看他们的访问日志与你联系。

  6. 例11.5, (3):之前你创建的 opener 对象也可以再生,且它将再次获得相同的 feed,但是使用了你自定义的 User-Agent 头信息。
    (./) 但这次使用了你自定义的 User-Agent; 头信息。

  7. 例11.5, (4):若你继续看,会注意到你定义的 User-Agent 头信息,你实际上发送了一个 User-agent 头信息。看看有何不同?urllib2 改变了大小写所以只有首字母是大写的。这没问题,因为 HTTP 规定头子段名完全是大小写无关的。
    (./) 若你继续看,会注意到你定义的 User-Agent 头信息,但实际上发送的是 User-agent 头信息。看看有何不同?urllib2 改变了大小写所以只有首字母是大写的。这没问题,因为 HTTP 规定头信息的字段名是大小写无关的。

11.6 处理 Last-Modified 和 ETag

  1. 作名词短语的调用程序一律改为主调程序

  2. Para 1:接下来看看 {i} 如何添加 Last-Modified 和 ETag 头信息的支持。

  3. 例11.6, (1):这里便是你如何以编程方式访问它们
    (./) 这里便是用编程方式访问它们的方法

  4. 例11.6, (3)You can see from the traceback that urllib2 throws a special exception, HTTPError, in response to the 304 status code.
    毫无疑问,数据没被改变。你可以从跟踪返回结果看到 urllib2 扔掉了特殊异常,HTTPError,响应中的 304 状态代码。
    (./) 毫无疑问,数据没被改变。你可以从跟踪返回结果看到 urllib2 抛出了一个特殊异常,HTTPError,以响应 304 状态代码。

  5. 例11.7上:urllib2 也为你认为是错误的其他条件引发 HTTPError 异常,……当你企图捕获状态代码并简单返回它,不抛弃任何异常时,这应该对你很有帮助。
    (./) urllib2 也为你认为是错误的其他条件引发 HTTPError 异常,……捕获状态代码并简单返回它,而不是抛出异常,这应该对你很有帮助。

  6. 例11.7, (1): 当某事件发生——比如一个 HTTP 错误,以至一个 304 代码——urllib2 审视用于处理它的 一系列已定义的处理器方法。你使用了一个与 第 9 章 XML 处理 类似的自省为不同节点类型定义了一些处理器,……
    (./) 当某事件发生时——比如一个 HTTP 错误,甚至是 304 代码——urllib2 审视用于处理它的 一系列已定义的处理器方法。在此要用到自省,与 第 9 章 XML 处理 中为不同节点类型定义不同处理器类似

  7. 例11.7, (2):当从服务器遇到 <!> 一个 304 状态代码,…… (./) 接收到

  8. 例11.8, (2):还记得我怎么说 urllib2 将一个 HTTP 资源的访问过程分解为三个步骤的正当理由吗?这便是为什么构建 HTTP 开启器就是它自身的步骤,……
    (./) 这便是为什么构建 HTTP 开启器是其步骤之一

  9. 例11.8, (3)Now you can quietly open the resource, and what you get back is an object that, along with the usual headers (use seconddatastream.headers.dict to acess them), also contains the HTTP status code. In this case, as you expected, the status is 304, meaning this data hasn't changed since the last time you asked for it.
    现在你可以快速地打开一个资源,返回给你的是,连同常规头信息在内的对象 (使用 seconddatastream.headers.dict 访问它们),也包括 HTTP 状态代码。在这种情况下,向你所期望的,状态代码是 304,意味着此数据自从上次请求后没有被修改。
    (./) 现在你可以快速地打开一个资源,返回给你的对象既包括常规头信息 (使用 seconddatastream.headers.dict 访问它们),也包括 HTTP 状态代码。在此,正如你所期望的,状态代码是 304,意味着此数据自从上次请求后没有被修改。

  10. 例11.8, (4):注意当服务器返回 304 状态代码时,并没有重新发送数据。这就是全部的关键:没有重新下载未修改的数据 {i} ,从而节省了带宽。

  11. 例11.8下:处理 ETag 的工作也非常相像,不是检查 Last-Modified 并发送 If-Modified-Since,而是检查 ETag 并发送 If-None-Match。
    (./) 处理 ETag 的工作也非常相似,只不过不是检查……

  12. 例11.9Supporting ETag/If-None-Match (./) 支持 ETag/If-None-Match

  13. 例11.9, (1):如果服务器没有返回 ETag 会发生什么?那么这一行将返回 None。
    (./) 答案是,这一行代码将返回 None。

  14. 例11.9, (5):无论 304 是否是被 Last-Modified 数据检查或 ETag hash 匹配触发的,你从来都不会连同数据一起获得 304
    (./) 无论 304 是被 Last-Modified 数据检查还是 ETag hash 匹配触发的,获得 304 的同时都不会下载数据

11.7 处理重定向

  1. 例11.10, (1)You'll be better able to see what's happening if you turn on debugging. 你最好看看开启调试状态时发生了什么。
    (./) 你最好开启调试状态,看看发生了什么。

  2. 例11.11上This is suboptimal, but easy to fix. urllib2 doesn't behave exactly as you want it to when it encounters a 301 or 302, so let's override its behavior. 这不太理想,但很容易改进。实际上当 urllib2 遇到 301 或 302 时并不做行为,所以让我们来覆盖这些行为。
    (./) 这不太理想,但很容易改进。实际上当 urllib2 遇到 301 或 302 时的行为并不是我们所期望的,所以让我们来覆盖这些行为。

  3. 例11.11, (1):重定向行为定义在 urllib2 的一个叫做 HTTPRedirectHandler 的类中。我们不想完全地覆盖这些行为,只想做点扩展,所以我们 {X} 子类化 HTTPRedirectHandler,从而我们仍然可以调用祖先类来实现所有原来的功能。

  4. 例11.11下:这将为我们带来什么?现在你可以构造一个用自定义重定向处理器的 URL 开启器,并且它依然能自动跟踪重定向,并且现在也能展示出重定向状态代码。
    (./) 这将为我们带来什么?现在你可以用自定义重定向处理器构造一个的 URL 开启器,并且它依然能自动跟踪重定向,也能展示出重定向状态代码。

  5. 例11.12, (3)The next time you request this data, you should request it from the new location (..., as specified in f.url)
    下一次你请求这个数据时,就应该在 f.url) 指定使用新地址……
    (./) 下一次你请求这个数据时,就应该使用 f.url 指定的新地址

  6. 例11.13, (1):这是一个 URL 的例子,我已经设置了它,配置它告知客户端为一个到 ... 的临时重定向
    (./) 这是一个 URL,我已经设置了它,让它告诉客户端临时重定向到...。

  7. 例11.13, (2):服务器返回 302 状态代码,标识出 {X} 一个临时重定向。

11.8 处理压缩数据

  1. 本节标题:处理压缩 {X} 数据

  2. 多处file 未译。

  3. 例11.15, (2)OK, this step is a little bit of messy workaround. python has a gzip module, which reads (and actually writes) gzip-compressed files on disk. ... So what you're going to do is create a file-like object out of the in-memory data (compresseddata), using the StringIO module.
    OK,只是先得有点儿凌乱的步骤。python 有 gzip 模块,它读取 (并实际写入) 磁盘上的 gzip 压缩文件。……那么怎么做来创建一个内存数据 (compresseddata) 之外的类文件对象呢,需要使用 StringIO 模块。
    (./) 好吧,只是先得有点儿凌乱的步骤。python 有一个 gzip 模块,它能读取 (当然也能写入) 磁盘上的 gzip 压缩文件。……那么怎么做来内存数据 (compresseddata) 创建类文件对象呢?这需要使用 StringIO 模块。
    (!) 值得注意的是,英文中的“OK”与中国人一般使用的“OK”意思不完全一样。“OK”的原义可表示让步,但中文中一般没有这种用法。

  4. 例11.15, (4):但 gzipper 还是真正的 {X} 从你用 StringIO 包装了压缩数据所创建的类文件对象中“读取”数据,……压缩的数据来自哪呢?你通常从远程 HTTP 服务器下载, (./) 最初

  5. 例11.16上:你在想那个 opener.open 返回一个类文件对象,那么为什么不抛弃中间件 StringIO 而通过 f 直接访问 GzipFile 呢?
    (./) 你在想,既然 opener.open 返回一个类文件对象,那么为什么不抛弃中间件 StringIO 而通过 f 直接访问 GzipFile 呢?

  6. 例11.16, (1):继续前面的例子,你已经有一个用 Accept-encoding: gzip 头信息设置的Request 对象。
    (./) 继续前面的例子,你已经有一个设置了 Accept-encoding: gzip 头信息的 Request 对象。

  7. 例11.16, (2):……这个数据已经被 gzip 压缩发送了
    (./) 这个数据被要求用 gzip 压缩发送(!) 从上下文看,此时还未发送数据。

  8. 例11.16, (3):从 opener.open 返回了一个类文件对象,并且阅读头信息你可以获知,……因为你从 GzipFile 实例“读取”,它将从远程 HTTP 服务器“读取”被压缩的数据并且立即解压缩。这是个好主意,但是不行的是它无法工作……所以使用 StringIO 这种看上去不雅的手段是最好的解决方案:下载压缩的数据,除此之外用 StringIO 创建一个类文件对象,……
    (./) 从 opener.open 返回了一个类文件对象,从头信息中你可以获知,……当你从 GzipFile 实例“读取”时,它将从远程 HTTP 服务器“读取”被压缩的数据并且立即解压缩。这是个好主意,但是不行……所以使用 StringIO 这种看上去不太优雅的手段是最好的解决方案:下载压缩的数据, StringIO 创建一个类文件对象,……
    (!) work 译为“工作”其实是很丑陋和无奈的译法,应当尽量避免出现。
    (!) “不太优雅”和“不雅”应该不是一个概念吧 :)

11.9 全部放在一起

  1. Para 1:你已经看到了构造一个职能 <!> 的 HTTP web 客户端的所有片断。 (./) 智能

  2. 例11.17, (1)urlparse is a handy utility module for, you guessed it, parsing URLs. It's primary function, also called urlparse,...
    urlparse 是一个解析 URL 的垂手可得的工具模块。它的主要功能也调用 urlparse,,获得一个 URL 并将其拆分为为一个包含 (scheme, domain, path, params, 查询串参数和验证片断) 的 tuple
    (./) urlparse 是一个解析 URL 的便捷的工具模块。它的主要函数也叫 urlparse,接受一个 URL 并将其拆分为 tuple (scheme (协议), domain (域名), path (路径), params (参数), query string parameters (请求字符串参数), fragment identifier (片段效验符))

  3. 例11.17, (6):使用两个自定义 URL 处理器创建一个 URL 开启器:SmartRedirectHandler 为了处理 301 和 302 重定向,而 DefaultErrorHandler 为了处理 304, 404 以及其它的错误条件。 (./) 用于

  4. 例11.17, (7):就 {i} 这样!

  5. 例11.18, (3):保存从服务器返回的 ETag hash,所以调用程序下一次能通过它返回给你,并且可以传递给 openAnything,连同 If-None-Match 头信息一起发送给远程服务器。
    (./) 保存从服务器返回的 ETag hash,这样主调程序下一次就能把它传递给你,然后再传递给 openAnything,放到 If-None-Match 头信息里发送给远程服务器。

  6. 例11.19, (1)真正 {X} 第一次获取资源时,你没有 ETag hash 或 Last-Modified 日期,……

  7. 例11.19, (3):……你需要更新你的 URL 到新地址(./) 你需要把你的 URL 更新为新地址

  8. 例11.19, (4):第二次获取相同的资源 {i} ,你已经从以往获得了各种信息:……

11.10 小结

  1. 每个客户端都应该支持的 5 个 HTTP web 服务重要特性
    (./) 每个客户端都应该支持 HTTP web 服务的以下 5 个重要特性

  2. 处理适当的永久重定向
    (./) 适当地处理永久重定向

DiveIntoPythonZh/2007-08-01 (last edited 2009-12-25 07:18:29 by localhost)