HTTPClient是httpclient.py中看到的第一个类。内容非常简单,但是却又没有看上去那么简单:
- fetch方法的实现会根据构造HTTPClient时传入的参数(async_client_class)发生变化。也就是说,HTTPClient并不是一个interface,而是一个delegator
- 每一个HTTPClient实例都会自己创建以及维护一个IOLoop。使用ioloop的目的,是为了实现异步的httprequest。这个ioloop会随着每一次fetch调用而start,request结束而stop,httpclient实例被销毁而close。
- 每一个HTTPClient会且只会对应一个async_client_class的实例。
在默认不传入任何参数的情况下,HTTPClient会选择AsyncHTTPClient作为默认的fetch engine。在tornado的注释里提到,HTTPClient只是为了方便使用,绝大多数情况下,application应该直接使用AsyncHTTPClient(可别搞混了,两者名字很像但根本不是继承关系)
AsyncHTTPClient理论上讲是一个abstract class,因为最重要的fetch方法,它并没有实现,而是依赖于子类(例如SimpleAsyncHTTPClient)的实现。AsyncHTTPClient重载了__new__方法,导致AsyncHTTPClient的对象创建过程显现出一种难以言语的诡异行为:
- 如果采用默认参数构造AsyncHTTPClient,得到的是一个SimpleAsyncHTTPClient对象的实例
- 如果在构造AsyncHTTPClient之前调用过AsyncHTTPClient.configure方法,可能会得到完全不同的另一个对象,例如AsyncHTTPClient.configure(async_client_class=CurlAsyncHTTPClient)
- 如果构造AsyncHTTPClient时全部使用默认参数,则每次得到的都是同一个对象的实例(如果此对象还没有在其他地方被析构删除)
- 如果构造AsyncHTTPClient时使用如下参数列表:force_instance=True,则每次得到的都是不同对象的实例。
- 如果构造AsyncHTTPClient时时每次传入不同的ioloop的实例,例如AsyncHTTPClient(IOLoop()),则不论是否设置force_instance=True,每次得到的也都是不同的实例。。。
根据上面的行为,得到两条结论:
- 一个AsyncHTTPClient(及其子孙类)的实例,对应且只能对应一个IOLoop;
- AsyncHTTPClient是一个可以实例化的有工厂的行为的“抽象类”(可以通过调用configure方法定义工厂的行为);
在tornado的注释中提到,对于SimpleAsyncHTTPClient,”It is intended to become the default AsyncHTTPClient implementation in a future release“。这个类非常简单木有啥好说的,只有三点有必要提一下:
- 这是一个实现了fetch方法的哥们
- 它继承自AsyncHTTPClient
- 它接受一个参数max_clients。别被它的名字弄糊涂了,这不是the maximum of clients,而是当前client实例的the maximum number of parall asynchronize fetch call!
稍微总结一下:
- HTTPClient是一个为了使用方便而定义的帮助类,提供的默认的callback方法会自动在每次fetch结束后清理资源。
- AsyncHTTPClient是一个”抽象类“
- SimpleAsyncHTTPClient和CurlAsyncHTTPClient是AsyncHTTPClient的子类,在直接使用这两个类的时候需要显示的制定Http请求的callback方法。