第3节,tornado自定义继承RequestHandler的类,处理http请求

使用tornado进行web编程的关键是自定义继承RequestHandler的子类并实现特定的方法,RequestHandler等价于flask框架里的视图,对RequestHandler的理解和使用将决定你能否掌握tornado框架。

1. self.request对象

处理客户端的请求,最重要的当然是获的请求的参数,这一点已经在获取请求参数那一篇教程中进行了讲解,除此以外,请求的headers也是十分重要的信息,与请求有关的信息都存储在self.request对象中

import tornado.ioloop
from tornado.web import RequestHandler, Application
from tornado.httpserver import HTTPServer
from tornado.options import options, define

define('port', default=8000, help='监听端口')


class HelloHandler(RequestHandler):
    def get(self):
        print(self.request.headers)             # 字典形式存储的headers信息
        print(self.request.headers['host'])     # 获取某一个首部
        print(self.request.path)                # 请求的path
        self.write('ok')


if __name__ == '__main__':
    options.parse_command_line()
    handlers_routes = [
        (r'/', HelloHandler)
    ]
    app = Application(handlers=handlers_routes)
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

self.request 对象的类型是HTTPServerRequest, 存在于tornado.httputil模块中,这个对象的属性不仅仅包含headers,还包括请求的method,uri, version,body, protocol, remote_ip,与请求有关的所有信息都包含在这个对象里,甚至包括最底层的socket连接,你所需要的信息都可以通过self.reqeust对象获取。

2. 一个请求对应一个RequestHandler对象

tornado每收到一个请求都会创建出一个RequestHandler对象对请求进行处理,这一点,可以通过实验来证实,我在处理get请求的方法里输出self对象的内存地址,每次请求到来时,输出的内存地址都是不相同的

class HelloHandler(RequestHandler):
    def get(self):
        print(id(self))
        self.write(str(id(self)))

3. initialize 与 prepare 有什么区别

initialize和prepare 是RequestHandler的两个很重要的方法,他们有什么功能作用,又有什么区别呢?

initialize 是框架预留的一个初始化时加载自定义内容的钩子,其会在http请求方法之前调用,prepare 在执行对应的请求方法之前调用。在执行顺序上,先是initialize而后是prepare方法。

initialize 处理从URLSpec接收到的参数,你可以在创建app时对initialize所能接收的参数进行设置,除此以外,你不能在initialize中做更多的事情,比如调用write, finish方法。

而在prepare里,你可以调用这些方法,假设你要写一个根据IP进行过滤的逻辑,那么你应该写在prepare方法里。在执行get或post之前在prepare方法里对客户端的IP进行过滤,如果发现IP不符合要求,则可以调用finish方法结束请求。注意,不要使用write方法,write方法在这里不会结束请求,你在这里write的内容会和后续处理请求的方法(get,或post)所返回的内容连接在一起返回。

下面的示例中,我在prepare方法里结束请求

import tornado
import tornado.ioloop
from tornado.web import RequestHandler
from tornado.web import URLSpec



class HelloHandler(RequestHandler):

    def initialize(self, db):
        print('initialize')
        self.db = db
        #  self.finish('over')  这里不可以调用finish

    def prepare(self):
        print('prepare')
        self.finish('over')

    def get(self):
        self.write(f'{self.db} ok')


url_handlers = [
    URLSpec(r'/hello', HelloHandler, {'db': 'mysql'})
]

app = tornado.web.Application(url_handlers)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(8990)
http_server.start()

tornado.ioloop.IOLoop.instance().start()

4. write与finish的区别

在第三节的例子里,处理请求的get方法使用write方法返回响应数据,而prepare方法里使用finish返回数据,这两个方法的区别是什么呢?

write和finish都可以向客户端返回数据,不同之处在于finish执行时,返回动作终结,如果你还有一些逻辑且这些逻辑和返回数据无关,那么你可以放在finish后面执行,对于客户端来说,它已经收到响应结果,你放在finish后面的逻辑所占用的时间与客户端无关。

write也是向客户端返回数据,但只有在遇到finish或者return后才会真正的向前端返回数据。因此,在处理请求的方法结束以前,你可以多次调用write方法,而finish则不可以。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案