5_structure_of_tornado_app
龙卷风 Web 应用程序的结构
龙卷风 Web 应用程序通常由一个或多个 RequestHandler 子类、一个将传入请求路由到处理程序的 Application 对象以及一个用于启动服务器的 main() 函数组成。
这是 Tornado Web 应用程序的示例
1 | import tornado.ioloop |
应用程序对象
Application 对象负责全局配置,包括将请求映射到处理程序的路由表。
路由表是 URLSepc 对象(或元组)的列表,每个对象包含一个正则表达式和一个处理程序类。订单事宜;使用第一个匹配规则。如果正则表达式包含捕获组,则这些组是路径参数,并将传递给处理程序的 HTTP 方法。如果字典作为 URLSpec 的第三个元素传递,它将提供将传递给 RequestHandler.initialize 的初始化参数,最后,URLSpec 可能有一个名称,这允许它与 RequestHandler.reverse_url 一起使用。
例如,在此片段中,根 URL / 映射到 MainHandler,而 /story/ 形式的 URL 后跟数字则映射到 StoryHandler。该数字(作为字符串)传递给 StoryHandler.get
1 | class MainHandler(RequestHandler): |
The Application constructor takes many keyword arguments that can be used to customize the behavior of the application and enable optional features.
Subclasses RequestHandler
Most of the work of a Tornado web app is done in the subclasses RequestHandler. The main entry point for a handler subclass is a method named after the HTTP method being handled: get(), post(), etc. Each handler may define one or more these methods to handle different HTTP actions. As described above, these methods will be called with arguments corresponding to the capturing groups of the routing rule that matched.
Within a handler, call methods such as RequestHandler.render or RequestHandler.wirte to produce a response. render() loads a Template by name and renders it with the given arguments. write() is used for non-template-based output; it accepts strings, bytes and dict(dict will be encoded as JSON).
Many methods in RequestHandler are designed to be overridden in subclasses and be used throughout the application. It is common to define a BaseHandler class that the overrides methods such as write_error and get_current_user and the subclass your own BaseHandler instead of RequestHandler for all your specific handlers.
Handling request input
The request handler can access the object representing the current request with self.request.
Request data in the formats used by HTML forms will be parsed for you and is made available in methods like get_query_argument and get_body_argument
1 | class MyFormHandler(RequestHandler): |
由于 HTML 表单编码对于参数是单个值还是包含一个元素的列表不明确,因此 RequestHandler 具有不同的方法来允许应用程序指示它是否需要一个列表。对于列表,请使用 get_query_arguments 和 get_body_arguments 而不是其单数对应项。
通过表单上传的文件在 self.request.files 中可用,它将名称(HTML <input type="file"> 元素的名称)映射到文件列表。每个文件都是 {"filename":..., "content_type":..., "body":...} 形式的字典。仅当文件是使用表单包装器上传时,文件对象才存在;如果未使用此格式,则原始上传数据可在 self.request.body 中使用。
默认情况下,上传的文件完全缓冲在内存中;如果您需要处理太大而无法轻松保存在内存中的文件,请参阅 stream_request_body 类装饰器。
重写 RequestHandler 方法
除了 get()/post() 之外,RequestHandler 中的某些其他方法被设计为在必要时由子类覆盖。对于每个请求,都会发生以下调用顺序:
- 每个请求都会创建一个新的RequestHandler 对象。
- 使用应用程序配置中的初始化参数调用initialize()。初始化通常应该只保存传递给成员变量的参数;它可能不会产生任何输出或调用诸如
send_error之类的方法
- 使用应用程序配置中的初始化参数调用initialize()。初始化通常应该只保存传递给成员变量的参数;它可能不会产生任何输出或调用诸如
- 调用 perpare()。这在所有处理程序子类共享的基类中最有用,因为无论使用哪种 HTTP 方法都会调用准备。准备可能会产生输出;如果它调用完成(或重定向等),则处理在此停止。
- 调用 HTTP 方法之一:get()、post()、put() 等。如果 URL 正则表达式包含捕获组,它们将作为参数传递给此方法。
- 当请求完成时,调用
on_finish()。对于大多数处理程序来说,这是在 get() 返回之后立即进行的;对于使用tornado.web.asynchronous装饰器的处理程序,它是在调用finish()之后。
- 当请求完成时,调用
所有设计为重写的方法都在 RequestHandler 文档中注明。一些最常见的重写方法包括:
write_error=> 输出 HTML 以在错误页面上使用on_connection_close=> 当客户端断开连接时调用;应用程序可以选择检测这种情况并停止进一步处理。请注意,不能保证可以立即检测到关闭的连接。get_current_userget_user_locale=> 返回当前用户使用的 Locale 对象。set_default_headers=> 可用于在响应上设置附加标头(例如自定义服务器处理程序)
错误处理
如果处理程序引发异常,Tornado 将调用 RequestHandler.write_error 来生成错误页面。 tornado.web.HTTPError 可用于生成指定的状态码;所有其他异常都会返回 500 状态。
默认错误页面包括调试模式下的堆栈跟踪和错误的一行描述(例如“500:内部服务器错误”)。要生成自定义错误页面,请覆盖 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。
重定向
Tornado 中有两种重定向请求的方法:RequestHandler.redirect 和 RedirectHandler。您可以在 RequestHandler 的子类中使用 self.redirect(),而 RedirectHandler 允许您在应用程序路由表中配置重定向。
1 | app = Application([ |
异步处理程序
您可以重写 RequestHandler 中的方法以使处理程序异步。例如,这是一个使用协程的简单处理程序:
1 | class MainHandler(RequestHandler): |