使用tornado进行web编程的关键是自定义继承RequestHandler的子类并实现特定的方法,RequestHandler等价于flask框架里的视图,对RequestHandler的理解和使用将决定你能否掌握tornado框架。
处理客户端的请求,最重要的当然是获的请求的参数,这一点已经在获取请求参数那一篇教程中进行了讲解,除此以外,请求的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对象获取。
tornado每收到一个请求都会创建出一个RequestHandler对象对请求进行处理,这一点,可以通过实验来证实,我在处理get请求的方法里输出self对象的内存地址,每次请求到来时,输出的内存地址都是不相同的
class HelloHandler(RequestHandler):
def get(self):
print(id(self))
self.write(str(id(self)))
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()
在第三节的例子里,处理请求的get方法使用write方法返回响应数据,而prepare方法里使用finish返回数据,这两个方法的区别是什么呢?
write和finish都可以向客户端返回数据,不同之处在于finish执行时,返回动作终结,如果你还有一些逻辑且这些逻辑和返回数据无关,那么你可以放在finish后面执行,对于客户端来说,它已经收到响应结果,你放在finish后面的逻辑所占用的时间与客户端无关。
write也是向客户端返回数据,但只有在遇到finish或者return后才会真正的向前端返回数据。因此,在处理请求的方法结束以前,你可以多次调用write方法,而finish则不可以。
QQ交流群: 211426309