最重要的一个模块是web, 它就是包含了 Tornado 的大部分主要功能的 Web 框架。其它的模块都是工具性质的, 以便让 web 模块更加有用 后面的 Tornado 攻略 详细讲解了 web 模块的使用方法。
web - FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能
escape - XHTML, JSON, URL 的编码/解码方法
database - 对 MySQLdb 的简单封装,使其更容易使用
template - 基于 Python 的 web 模板系统
httpclient - 非阻塞式 HTTP 客户端,它被设计用来和 web 及 httpserver 协同工作
auth - 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)
locale - 针对本地化和翻译的支持
options - 命令行和配置文件解析工具,针对服务器环境做了优化
httpserver - 服务于 web 模块的一个非常简单的 HTTP 服务器的实现
iostream - 对非阻塞式的 socket 的简单封装,以方便常用读写操作
ioloop - 核心的 I/O 循环
Tornado 的 Web 程序会将 URL 或者 URL 范式映射到 tornado.web.RequestHandler 的子类上去。在其子类中定义了 get() 或 post() 方法,用以处理不同的 HTTP 请求。
下面的代码将 URL 根目录 / 映射到 MainHandler,还将一个 URL 范式 /story/([0-9]+) 映射到 StoryHandler。正则表达式匹配的分组会作为参数引入 的相应方法中:
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("You requested the main page")
class StoryHandler(tornado.web.RequestHandler):
def get(self, story_id):
self.write("You requested the story " + story_id)
application = tornado.web.Application([
(r"/", MainHandler),
(r"/story/([0-9]+)", StoryHandler),
])
你可以使用 get_argument() 方法来获取查询字符串参数,以及解析 POST 的内容:
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('<html><body><form action="/" method="post">'
'<input type="text" name="message">'
'<input type="submit" value="Submit">'
'</form></body></html>')
def post(self):
self.set_header("Content-Type", "text/plain")
self.write("You wrote " + self.get_argument("message"))
如果你想要返回一个错误信息给客户端,例如“403 unauthorized”,只需要抛出一个 tornado.web.HTTPError 异常:
if not self.user_is_logged_in():
raise tornado.web.HTTPError(403)
除了 get()/post()等以外,RequestHandler 中的一些别的方法函数,这都是 一些空函数,它们存在的目的是在必要时在子类中重新定义其内容。对于一个请求的处理 的代码调用次序如下:
1.程序为每一个请求创建一个 RequestHandler 对象
2.程序调用 initialize() 函数,这个函数的参数是 Application 配置中的关键字 参数定义。(initialize 方法是 Tornado 1.1 中新添加的,旧版本中你需要 重写 __init__ 以达到同样的目的) initialize 方法一般只是把传入的参数存 到成员变量中,而不会产生一些输出或者调用像 send_error 之类的方法。
3.程序调用 prepare()。无论使用了哪种 HTTP 方法,prepare 都会被调用到,因此 这个方法通常会被定义在一个基类中,然后在子类中重用。prepare可以产生输出 信息。如果它调用了finish(或send_error` 等函数),那么整个处理流程 就此结束。
4.程序调用某个 HTTP 方法:例如 get()、post()、put() 等。如果 URL 的正则表达式模式中有分组匹配,那么相关匹配会作为参数传入方法。
Tornado 中的重定向有两种主要方法:self.redirect,或者使用 RedirectHandler。
你可以在使用 RequestHandler (例如 get)的方法中使用 self.redirect,将用户 重定向到别的地方。另外还有一个可选参数 permanent,你可以用它指定这次操作为永久性重定向
该参数会激发一个 301 Moved Permanently HTTP 状态,这在某些情况下是有用的, 例如,你要将页面的原始链接重定向时,这种方式会更有利于搜索引擎优化(SEO)。
permanent 的默认值是 False,这是为了适用于常见的操作,例如用户端在成功发送 POST 请求 以后的重定向。
self.redirect('/some-canonical-page', permanent=True)
RedirectHandler 的默认状态码是 301 Moved Permanently,不过如果你想使用 302 Found 状态码,你需要将 permanent 设置为 False。
注意,在 self.redirect 和 RedirectHandler 中,permanent 的默认值是不同的。 这样做是有一定道理的,self.redirect 通常会被用在自定义方法中,是由逻辑事件触发 的(例如环境变更、用户认证、以及表单提交)。而 RedirectHandler 是在每次匹配到请求 URL 时被触发。
当一个处理请求的行为被执行之后,这个请求会自动地结束。因为 Tornado 当中使用了 一种非阻塞式的 I/O 模型,所以你可以改变这种默认的处理行为——让一个请求一直保持 连接状态,而不是马上返回,直到一个主处理行为返回。要实现这种处理方式,只需要 使用 tornado.web.asynchronous 装饰器就可以了。
使用了这个装饰器之后,你必须调用 self.finish() 已完成 HTTTP 请求,否则 用户的浏览器会一直处于等待服务器响应的状态:
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
self.write("Hello, world")
self.finish()
下面是一个使用 Tornado 内置的异步请求 HTTP 客户端去调用 FriendFeed 的 API 的例 子:
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
http = tornado.httpclient.AsyncHTTPClient()
http.fetch("http://friendfeed-api.com/v2/feed/bret",
callback=self.on_response)
def on_response(self, response):
if response.error: raise tornado.web.HTTPError(500)
json = tornado.escape.json_decode(response.body)
self.write("Fetched " + str(len(json["entries"])) + " entries "
"from the FriendFeed API")
self.finish()
例子中,当 get() 方法返回时,请求处理还没有完成。在 HTTP 客户端执行它的回 调函数 on_response() 时,从浏览器过来的请求仍然是存在的,只有在显式调用了 self.finish() 之后,才会把响应返回到浏览器。