`

tornado: web.py 之 RequestHandler

 
阅读更多

RequestHandler这个类有超过1000行,看似十一个庞然大物,其实大多是注释和空方法,总体读起来非常容易。

 

这个类也是blog项目中所有handler的父类,想必大多数tornado项目也是如此,当然顾名思义这个类以及它的派生类用来处理tornado web server收到的httprequest,目前为止还没有看到httpserver的代码,无责任随便猜测一下,一个httprequest处理的大概流程:

  1. Httpserver收到请求
  2. 扔给Application实例去处理(调用__call__)
  3. 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等方法
分享到:
评论

相关推荐

    PyPI 官网下载 | tornado-1.0.tar.gz

    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...

    关于服务器——安装配置tornado

    class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application....

    python测验,hello-tornado.rar

    2. **处理器类**(如`handlers.py`):这些是处理特定URL请求的类,继承自`tornado.web.RequestHandler`。每个类通常有一个`get`或`post`方法来处理HTTP请求。 3. **模板文件**(如`templates/index.html`):...

    tornado 简单项目结构

    2. **路由 (handlers)**:在 Tornado 中,路由是通过处理器(Handler)类来定义的,这些类继承自 `tornado.web.RequestHandler`。每个处理器类对应一个 URL,负责处理特定的 HTTP 请求。例如,你可能会有一个 `index...

    使用Nginx_Supervisor_tornado搭建web服务.pdf

    from tornado.web import Application, RequestHandler class MainHandler(RequestHandler): def get(self): self.write("Hello, world!") if __name__ == "__main__": application = Application([ (r"/", ...

    tornado中文文档

    Tornado 的设计灵感来源于 web.py 和 Google 的 webapp,但为了充分利用非阻塞服务器的优势,它增加了一系列特有工具和优化。 **基础概念** 1. **非阻塞I/O**:Tornado 使用非阻塞I/O模型,通过事件驱动和epoll...

    tornado实例todo

    本实例将探讨如何使用Tornado框架来实现一个简单的Todo应用,它是基于Web.py的Todo应用的改写版本。 首先,我们需要了解Tornado的基础架构。Tornado的核心组件包括`HTTPServer`、`RequestHandler`和`Application`。...

    tornado框架手打

    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

    PythonWeb.zip是一个包含使用Python语言和Tornado框架构建的Web应用程序的压缩文件。Tornado是一个开源的、高性能的Web服务器和异步网络库,最初由FriendFeed开发,并被Facebook收购后进一步发展。它以其轻量级、可...

    tornado实战之一

    **正文** ...总的来说,"Tornado实战之一"将引导你逐步进入Tornado的世界,让你理解其核心概念和用法,为更复杂的Web应用开发打下坚实基础。通过实践,你将学会如何构建高效、响应迅速的Python Web服务。

    tornado项目模板

    每个处理程序类继承自`tornado.web.RequestHandler`,并在其中定义`get`、`post`等方法来处理HTTP请求。 3. **数据库操作** Tornado自身不提供数据库抽象层,但可以与各种ORM(对象关系映射)工具结合使用,如...

    python tornado实例

    Python Tornado是一个强大的异步网络库,用于构建高性能、高并发的Web服务。Tornado以其非阻塞I/O和事件驱动的模型而闻名,尤其适合实时Web应用,如聊天、实时图表或者推送通知等。在Eclipse + PyDev环境下开发...

    标准的Tornado项目结构

    - `handlers`:存放处理 HTTP 请求的类,这些类通常继承自 `tornado.web.RequestHandler`。 - `models`:用于数据库交互和数据模型定义。 - `services`:存放业务逻辑代码,与特定的 HTTP 请求处理分离。 - `utils`...

    Python-dbpy灵感来自webpy和drupal通用数据库抽象层

    Python的dbpy是一个灵感来源于webpy和drupal的通用数据库抽象层,它的设计目标是提供一个灵活且易于使用的接口,让开发者能够轻松地在不同的Web框架(如tornado)和其他环境中处理数据库操作。ORM(Object-...

    Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法

    - 在Tornado中,Web服务器通常基于`Application`和`RequestHandler`。你需要定义路由和对应的处理器,比如创建一个`IndexHandler`来处理根路径请求,然后在`Application`中注册这个处理器。 - 如果需要与Socket...

    Python库 | tornado_eventsource-0.1.4.tar.gz

    from tornado.web import Application, RequestHandler from tornado.eventsource import EventSourceHandler class SSEHandler(EventSourceHandler): def data_received(self, data): # 假设data是新接收到的...

    tornado-quick-setup:在进行一些配置之后,按照自述文件,基于龙卷风的Web服务将运行

    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源代码

    Tornado 是一个强大的、高性能的 Web 服务器和异步网络库,由 Python 语言编写。尽管您的描述提到“tornado 是一款纯 Java 开发的”,但实际上是错误的,Tornado 实际上是 Python 的一个开源项目。它以其非阻塞 I/O ...

    【Tornado】使用tornado写API的增删改查(一)

    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....

    Python的Tornado框架实现异步非阻塞访问数据库的示例

    class BaseHandler(tornado.web.RequestHandler): @property def db(self): return self.application.db ``` 现在,我们创建两个处理器`RegisterHandler`和`LoginHandler`,它们都将使用异步方法来处理用户注册...

Global site tag (gtag.js) - Google Analytics