Tornado web应用程序通常由一个或多个 RequestHandler 子类组成,将传入请求路由到处理程序的 Application 对象,和一个启动服务程序的 main 方法。
一个最小的“hello world”示例是这样的:
1  | import tornado.ioloop  | 
Application 对象
Application 对象负责全局配置,包括将请求映射到处理程序的路由表。
路由表是 URLSpec 对象(或元组)的列表,每个对象都包含(至少)一个正则表达式和一个处理程序类。顺序问题:使用第一个匹配规则。如果正则表达式包含捕获组,那么这些组就是路径参数,并将被传递给处理程序的HTTP方法。如果字典作为 URLSpec 的第三个元素传递,它将提供初始化参数,该参数将被传递给 RequestHandler.initialize。URLSpec 对象也可自定义名称,用于 RequestHandler.reverse_url。
例如,在这个片段中,根URL / 被映射到 MainHandler,而形式 /story/ 后面跟着一个数字的 URL 被映射到 StoryHandler。这个数字被传递(作为字符串)给 StoryHandler.get。
1  | class MainHandler(RequestHandler):  | 
Application 构造函数接受许多关键字参数,这些参数可用于自定义应用程序的行为和启用可选特性;点击 Application.settings,查看完整设置。
RequestHandler 子类
Tornado web应用程序的大部分工作都是在 RequestHandler 的子类中完成的。处理程序子类的主要入口点是以被处理的HTTP方法命名的方法: get()、post()等。每个处理程序可以定义一个或多个这样的方法来处理不同的HTTP操作。如上所述,这些方法将被调用,参数与匹配的路由规则的捕获组相对应。
在处理程序中,调用 RequestHandler.render、RequestHandler.write来产生一个响应。render() 按名称加载模板,并使用给定参数呈现它。write() 用于非基于模板的输出;它接受字符串、字节和字典(dicts将被编码为JSON)。
RequestHandler 中的许多方法被设计成可以在子类中重写,并在整个应用程序中使用。通常定义一个 BaseHandler 类,覆盖 write_error 和 get_current_user 等方法,然后为所有特定的处理程序子类化你自己的 BaseHandler 而不是 RequestHandler。
处理请求输入
请求处理程序可以通过 self.request 访问表示当前请求的对象。有关属性的完整列表,请参阅 HTTPServerRequest 的类定义。
HTML表单使用的格式的请求数据将为您解析,并在 get_query_argument 和 get_body_argument 等方法中可用。
1  | class MyFormHandler(tornado.web.RequestHandler):  | 
由于HTML表单编码对于参数是单个值还是包含一个元素的列表是模棱两可的,RequestHandler 提供了不同的方法,允许应用程序指示它是否需要列表。对于列表,使用 get_query_arguments 和 get_body_arguments 而不是它们的单一对应项。
通过表单上传的文件在 self.request.files 中可用。它将名称 <input type="file"> 元素映射到一个文件列表。每个文件是一个字典形式 {"filename":…, "content_type":……, "body":…}。files 对象只有在文件上传带有表单包装器(即 multipart/form-data 类型)时才存在;如果未使用此格式,则在 self.request.body 中可以使用原始上传数据。默认情况下,上传的文件在内存中完全缓冲;如果您需要处理太大而不能舒适地保存在内存中的文件,请参阅 stream_request_body 类装饰器。
在demos目录中,file_receiver.py显示了两种接收文件上传的方法。
由于HTML表单编码的奇怪之处(例如,单参数与复数参数之间的模糊性),Tornado并不试图将表单参数与其他类型的输入统一起来。特别地,我们不解析JSON请求体。希望使用JSON而不是form-encoding的应用程序可以重写 prepare 来解析它们的请求:
1  | def prepare(self):  | 
重写RequestHandler方法
除了 get()/ post()/等,RequestHandler 中的某些其他方法被设计成在必要时由子类覆盖。在每个请求中,会发生以下调用序列:
- 每个请求都会创建一个新的 
RequestHandler对象。 initialize()使用来自应用程序配置的初始化参数调用。初始化通常应该只保存传递给成员变量的实参;它可能不会产生任何输出或调用send_error之类的方法。prepare()被调用。这在所有处理程序子类共享的基类中最有用,因为无论使用哪种HTTP方法都将调用prepare。准备可产生产出;如果它调用finish(或redirect,等等),处理将在此停止。- 其中一个HTTP方法被调用:
get()、post()、put()等等。如果URL正则表达式包含捕获组,则将它们作为参数传递给此方法。 - 当请求完成时,调用
on_finish()。这通常是在get()或另一个HTTP方法返回之后。 
所有设计要重写的方法都在RequestHandler文档中有这样的说明。一些最常见的覆盖方法包括:
write_error- 输出用于错误页面的HTML。on_connection_close- 当客户端断开连接时调用;应用程序可以选择检测这种情况并停止进一步处理。请注意,不能保证能够迅速检测到关闭的连接。get_current_user- 参见User authentication。get_user_locale- 返回用于当前用户的Locale对象。set_default_headers- 可以用于设置响应的附加标头(例如自定义Server头)。
错误处理
如果处理程序抛出异常,Tornado将调用RequestHandler.write_error生成一个错误页面。tornado.web.HTTPError可以用来生成指定的状态码;所有其他异常返回一个500状态。
默认的错误页面包括调试模式下的堆栈跟踪和错误的单行描述(例如:“500: Internal Server Error”)。若要生成自定义错误页面,请覆盖RequestHandler.write_error(可能在所有处理程序共享的基类中)。该方法可以通过write和render等方法正常生成输出。如果错误是由异常引起的,那么将传递一个exc_info三元组作为关键字参数(注意,这个异常不能保证是sys.exc_info,所以write_error必须使用traceback.format_exception代替traceback.format_exc)。
通过调用set_status编写响应并返回,也可以从常规处理程序方法而不是write_error生成一个错误页面。在简便返回不很方便的情况下tornado.web.Finish 异常会被抛出来终止处理程序而不是抛出write_error。
对于404错误,使用default_handler_class Application settings。这个处理程序应该覆盖prepare而不是像get()这样更具体的方法,这样它就可以与任何HTTP方法一起工作。它应该像上面描述的那样生成它的错误页面:通过调用HTTPError(404)并覆盖write_error,或者调用self.set_status(404)并在prepare()中直接生成响应。
重定向
在Tornado中有两种主要的重定向请求的方法:RequestHandler.redirect 和 RedirectHandler。
您可以在RequestHandler方法中使用self.redirect()将用户重定向到其他地方。还有一个可选参数permanent,您可以使用它来指示重定向被认为是永久性的。permanent的默认值是False,它生成302 Found HTTP响应代码,适合在成功POST请求后重定向用户。如果permanent为True,则使用301移动的永久HTTP响应代码,这在以面向seo的方式重定向到页面的规范URL时很有用。
RedirectHandler允许您在应用程序路由表中直接配置重定向。例如,要配置一个静态重定向:
1  | app = tornado.web.Application([  | 
RedirectHandler也支持正则表达式替换。下面的规则将所有以/pictures/开头的请求重定向到前缀/photos/:
1  | app = tornado.web.Application([  | 
不像RequestHandler.redirect,RedirectHandler默认使用永久重定向。这是因为路由表在运行时不会改变,并且被认为是永久的,而在处理程序中发现的重定向很可能是其他可能改变的逻辑的结果。要使用RedirectHandler发送临时重定向,请在RedirectHandler初始化参数中添加permanent=False。
异步处理类
某些处理程序方法(包括prepare()和HTTP动词方法get()/ post()/等)可能被重写为协程,以使处理程序异步。
例如,下面是一个使用协同程序的简单处理程序:
1  | class MainHandler(tornado.web.RequestHandler):  | 
关于更高级的异步示例,请查看聊天示例应用程序,该应用程序使用长轮询实现了一个AJAX聊天室。使用长轮询的用户可能希望覆盖on_connection_close(),以便在客户端关闭连接后进行清理(但请参阅该方法的文档字符串以了解注意事项)。
Read More: