RequestHandler这个类有超过1000行,看似十一个庞然大物,其实大多是注释和空方法,总体读起来非常容易。
这个类也是blog项目中所有handler的父类,想必大多数tornado项目也是如此,当然顾名思义这个类以及它的派生类用来处理tornado web server收到的httprequest,目前为止还没有看到httpserver的代码,无责任随便猜测一下,一个httprequest处理的大概流程:
- Httpserver收到请求
- 扔给Application实例去处理(调用__call__)
- Application的实例根据初始化时(或者后来通过add_handler添加的)路由表,生成相应的handler实例,把request扔进去进行处理。
目前默认tornado支持如下几种方法:
SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS")
貌似比几年前看得REST要多好几个啊。。。。head,patch,options是什么情况?
这个类因为是基础类,所以所以定义了一堆空方法,有几个方法值得拿出来单独列在这里的(虽然在基类中并没有任何实现)
def prepare(self): """Called at the beginning of a request before `get`/`post`/etc. Override this method to perform common initialization regardless of the request method. """ pass def on_finish(self): """Called after the end of a request. Override this method to perform cleanup, logging, etc. This method is a counterpart to `prepare`. ``on_finish`` may not produce any output, as it is called after the response has been sent to the client. """ pass def on_connection_close(self): """Called in async handlers if the client closed the connection. Override this to clean up resources associated with long-lived connections. Note that this method is called only if the connection was closed during asynchronous processing; if you need to do cleanup after every request override `on_finish` instead. Proxies may keep a connection open for a time (perhaps indefinitely) after the client has gone away, so this method may not be called promptly after the end user closes their connection. """ pass
基本上提供了某种程度上的callback,俺没有任何tornado经验,不知到有多少项目中真正用到了。
比较诡异的是,这个类里面定义了一些看起来重复的变量,比如下面两个
# UIModules are available as both `modules` and `_modules` in the # template namespace. Historically only `modules` was available # but could be clobbered by user additions to the namespace. # The template {% module %} directive looks in `_modules` to avoid # possible conflicts. self.ui["_modules"] = ObjectDict((n, self._ui_module(n, m)) for n, m in application.ui_modules.iteritems()) self.ui["modules"] = self.ui["_modules"]
还有这两个方法中用到的两个成员变量。。。
def set_header(self, name, value): """Sets the given response header name and value. If a datetime is given, we automatically format it according to the HTTP specification. If the value is not a string, we convert it to a string. All header values are then encoded as UTF-8. """ self._headers[name] = self._convert_header_value(value) def add_header(self, name, value): """Adds the given response header and value. Unlike `set_header`, `add_header` may be called multiple times to return multiple values for the same header. """ self._list_headers.append((name, self._convert_header_value(value)))
尼嘛意义何在啊啊。。。还没看到后面,暂时还理解不了。
然后下面是一些已经实现的方法,其中比较重要的一个个拿出来说说
- set_cookie
在handle中初始化一个名为_new_cookie的SimpleCookie实例,然后根据传入的参数设置domain, expires, path, max-age, 以及其他用户自定义的cookie pair - clear_cookie
这个方法挺有意思,clear的意思并不是“clear”,而是通过设置cookie的expire time让客户端浏览器中把cookie删除,而不是server端(本来清除cookie就是应该这么干吧?) - set_secure_cookie
这个方法会用Application.Settings中设置的secret来产生经过加密的cookie - get_secure_cookie
这是上面方法的配对方法 - redirect
设置response header中的location,并设置http status为3xx,这样的response一旦返回,浏览器默认会触发重定向到location中指定的url (看成中指的请自觉面壁) - write
这个方法的注释说的很清楚了。。。"""Writes the given chunk to the output buffer. To write the output to the network, use the flush() method below. If the given chunk is a dictionary, we write it as JSON and set the Content-Type of the response to be application/json. (if you want to send JSON as a different Content-Type, call set_header *after* calling write()). Note that lists are not converted to JSON because of a potential cross-site security vulnerability. All JSON output should be wrapped in a dictionary. More details at http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx """
- render
这是个很重要函数,用来根据指定的模板生成最终的渲染页面。因为太长了,所以我跳过去了,以后回头看。 - render_string
这也是一个很重要的函数,不太长,但是看了一下。。。没看懂。。。主要是没明白template神码的是怎么回事。。其中一个term叫做template的namespace,我怎么看怎么不应该叫namespace,似乎叫context更加合适。。。。不信你看。。。namespace = dict( handler=self, request=self.request, current_user=self.current_user, locale=self.locale, =self.locale.translate, static_url=self.static_url, xsrf_form_html=self.xsrf_form_html, reverse_url=self.reverse_url) namespace.update(self.ui)
- flush
基本上这个方法会把buffer里面的东东弄出来调用注册的transform变成data chunk,生成header,最后调用httprequest的write方法写回到客户端 - finish
flush方法才真正的把数据写入request中(总觉的是不是用一个单独的response会比较不让人糊涂?),但是不会调用request的finish方法,而这些是在finish方法中调用的。所以一个request最后一个调用的一定是finish方法来结束请求。在finish方法内部也会调用flush,不过如果在finish之前调用过flush,行为可能是不确定的,大概会取决于传入flush方法的callback方法如何实现。但从代码来看,请不要在在代码中调用flush,这种粗重活,让finish来做好了。有一点需要注意的是,handler中某些方法的默认实现是会帮我们调用finish的,所以不用调用第二遍,否则会抛出exception,这些方法包括:
1. redirect
2. send_error
3. write_error - send_error
这个方法主要依赖write_error来产生错误页面返回用户 - write_error
看了一下代码,觉得自定义在handler中自定义一个get_error_html方法的做法比较靠谱 - locale
这个property在内部可能会调用两个不同的方法
1. self.get_user_locale
2. self.get_browser_locale
其中第一个方法默认没有提供实现,不过可以由程序员重载。提供两个方法的主要目的大概是:第一个方法不去理会浏览器中的language参数,而是从某个其他的地方,例如从数据库中读取用户设置的语言偏好(常用代理的同学应该体会比较深);第二个方法顾名思义,从用户request的header中读取Accept-language来决定用户的locale。 只有第一个方法调用失败或者返回None的情况下才会调用第二个方法。 - current_user
获取当前用户信息。默认提供的时候屁事没干,所以如果你需要用这个方法来做用户身份认证,获取用户信息的话,需要重载self.get_current_user方法。 - get_login_url
获得定义在Application.Settings中的get_login_url地址 - get_template_path
获得定义在Application.Settings中的get_template_path。这个路径应该是一个绝对路径,指向存放template文件的目录,或者返回None,用于从当前文件的相对路径开始查找。 - xsrf_token
property获得xsrf_token,用于防止forgery攻击。这个xsrf_token会同时保存在用户浏览器的cookie中,以及当前handler的_xsrf_token属性中,用于对接下来用户post消息的验证。不过这个实现我有点儿糊涂--如果用户cookie被盗怎么办?在设置用户cookie的时候至少用set_secure_cookie吧? - check_xsrf_cookie
检查参数中是否携带_xsrf, 或者header中包含X-Xsrftoken, X-Csrftoken。如果存在,再和handle中保存的值比较。 - xsrf_form_html
helper方法,生成一个hidden的form item代码片段,会随着form被post给server,也就是在check_xsrf_cookie中会检查的东东 - _execute
根据http类型分别调用handle中的get, post, delete, edit等方法
相关推荐
class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app...
class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application....
2. **处理器类**(如`handlers.py`):这些是处理特定URL请求的类,继承自`tornado.web.RequestHandler`。每个类通常有一个`get`或`post`方法来处理HTTP请求。 3. **模板文件**(如`templates/index.html`):...
2. **路由 (handlers)**:在 Tornado 中,路由是通过处理器(Handler)类来定义的,这些类继承自 `tornado.web.RequestHandler`。每个处理器类对应一个 URL,负责处理特定的 HTTP 请求。例如,你可能会有一个 `index...
from tornado.web import Application, RequestHandler class MainHandler(RequestHandler): def get(self): self.write("Hello, world!") if __name__ == "__main__": application = Application([ (r"/", ...
Tornado 的设计灵感来源于 web.py 和 Google 的 webapp,但为了充分利用非阻塞服务器的优势,它增加了一系列特有工具和优化。 **基础概念** 1. **非阻塞I/O**:Tornado 使用非阻塞I/O模型,通过事件驱动和epoll...
本实例将探讨如何使用Tornado框架来实现一个简单的Todo应用,它是基于Web.py的Todo应用的改写版本。 首先,我们需要了解Tornado的基础架构。Tornado的核心组件包括`HTTPServer`、`RequestHandler`和`Application`。...
class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app...
PythonWeb.zip是一个包含使用Python语言和Tornado框架构建的Web应用程序的压缩文件。Tornado是一个开源的、高性能的Web服务器和异步网络库,最初由FriendFeed开发,并被Facebook收购后进一步发展。它以其轻量级、可...
**正文** ...总的来说,"Tornado实战之一"将引导你逐步进入Tornado的世界,让你理解其核心概念和用法,为更复杂的Web应用开发打下坚实基础。通过实践,你将学会如何构建高效、响应迅速的Python Web服务。
每个处理程序类继承自`tornado.web.RequestHandler`,并在其中定义`get`、`post`等方法来处理HTTP请求。 3. **数据库操作** Tornado自身不提供数据库抽象层,但可以与各种ORM(对象关系映射)工具结合使用,如...
Python Tornado是一个强大的异步网络库,用于构建高性能、高并发的Web服务。Tornado以其非阻塞I/O和事件驱动的模型而闻名,尤其适合实时Web应用,如聊天、实时图表或者推送通知等。在Eclipse + PyDev环境下开发...
- `handlers`:存放处理 HTTP 请求的类,这些类通常继承自 `tornado.web.RequestHandler`。 - `models`:用于数据库交互和数据模型定义。 - `services`:存放业务逻辑代码,与特定的 HTTP 请求处理分离。 - `utils`...
Python的dbpy是一个灵感来源于webpy和drupal的通用数据库抽象层,它的设计目标是提供一个灵活且易于使用的接口,让开发者能够轻松地在不同的Web框架(如tornado)和其他环境中处理数据库操作。ORM(Object-...
- 在Tornado中,Web服务器通常基于`Application`和`RequestHandler`。你需要定义路由和对应的处理器,比如创建一个`IndexHandler`来处理根路径请求,然后在`Application`中注册这个处理器。 - 如果需要与Socket...
from tornado.web import Application, RequestHandler from tornado.eventsource import EventSourceHandler class SSEHandler(EventSourceHandler): def data_received(self, data): # 假设data是新接收到的...
class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": ...
Tornado 是一个强大的、高性能的 Web 服务器和异步网络库,由 Python 语言编写。尽管您的描述提到“tornado 是一款纯 Java 开发的”,但实际上是错误的,Tornado 实际上是 Python 的一个开源项目。它以其非阻塞 I/O ...
class GetALlBlog(tornado.web.RequestHandler): def initialize(self, db): self.db = db def get(self): db = self.db cursor = db.cursor(pymysql.cursors.DictCursor) try: # SQL 查询语句 cursor....
class BaseHandler(tornado.web.RequestHandler): @property def db(self): return self.application.db ``` 现在,我们创建两个处理器`RegisterHandler`和`LoginHandler`,它们都将使用异步方法来处理用户注册...