目录
一、在Handler.on_finish部分记录每次接口请求的路径、时间、耗时,输出日志。
二、重写Handler中的get和post方法,实现请求能够分发到Handler的不同处理函数。
前言
还没有接触过Tornado框架的可以看这章:
没有学习过框架的同学可以先看看下面这个视频教程:
以及网页教程:
本章我们要在Tornado框架中实现两个功能:
一、在Handler.on_finish部分记录每次接口请求的路径、时间、耗时,输出日志。
二、重写Handler中的get和post方法,实现请求能够分发到Handler的不同处理函数。
一、在Handler.on_finish部分记录每次接口请求的路径、时间、耗时,输出日志。
1、首先,Handler.on_finish部分是什么?
我们访问网页时的请求都是通过请求处理器来对我们的请求进行处理,从而返回对应的操作,在Tornado框架中,我们通过不同路由来响应不同的请求,不同请求有着对应的处理器(Handler)来对它们进行处理,这些处理器都继承同一个父类:Tornado.web中的RequsetHandler类。我们通过command+鼠标左键点击,即可查看RequestHandler中的对应方法。
其中,我们可以看到get,post,on_finish方法等。
根据英文提示,我们可以看到在on_finish方法里,提示我们可以通过重写此方法来进行进程的清空,日志的记录和输出等。
关于日志(logging),没有学习过的小伙伴可以看这篇:
要在Handler中实现日志的输出与打印,我们可以用到python自带的logging包,用import logging命令即可调用。
# 调用tornado库
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
import logging
# Hello处理器
class HelloHandler(RequestHandler):
# 日志方法
def log(self,msg): # msg为日志输出的信息
logger = logging.getLogger('logger')
logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
# 规定日志保存的路径
file_handler = logging.FileHandler('../test2/logs/log.txt')
file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info(msg)
# get方法重写
def get(self):
self.write("Hello,world")
# on_finish方法重写
def on_finish(self):
# 获取请求路径,请求方法,请求头,拼接成字符串,传入log方法,作为日志所保存的内容
msg = str(self.request.path) + str(self.request.method) + str(self.request.headers)
# 调用log方法
self.log(msg)
# 路由设置
app = Application([
(r"/", HelloHandler),
])
# 程序启动
if __name__ == "__main__":
# 设置端口号
app.listen(8888)
IOLoop.current().start()
然后再次在浏览器中输入网址来测试我们的代码是否成功实现日志功能,可以看到,在控制台中已经输出了我们的日志信息:
然后打开我们logs文件夹中的log.txt,也可以查看到我们的日志信息:
注意,在运行文件时,首先要确保是否存在对应的文件夹来让日志进行保存,没有的话需要创建,不然运行时会报错。
二、重写Handler中的get和post方法,实现请求能够分发到Handler的不同处理函数。
上面介绍过我们可以通过command+鼠标左键来查看类或者方法,可以看到Tornado.web的RequestHandler类中存在get和post方法,下面先简单介绍一下它们:
get和post可以理解成传递请求参数的不同方法,get传递的参数一般是用于查询的参数,get请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,并且get的长度受限于url的长度,而url的长度限制是特定的浏览器和服务器设置的,理论上get的长度可以无限长。
post把提交的数据则放置在是HTTP包的包体中,post是没有大小限制的,HTTP协议规范也没有进行大小限制,起限制作用的是服务器的处理程序的处理能力,post一般处理私密性的信息,如登陆账户,修改密码等私密性操作。
要实现用get和post请求来实现请求能够分发到Handler的不同处理函数,这里就牵扯到怎么实现接口的调用了,那么,什么是接口呢?
接口是一种用来定义程序的协议,描述可属于任何类或结构的一组相关行为
按理解来说,接口是后端处理数据然后返回的一个连接处,接着前端可以通过这个接口拿到后端的数据。在Handler中,我们可以把接口理解成一种处理请求的方法,不同的接口对应着不同的请求处理方法。
首先,想要实现请求的分发,就需要在get和post方法中对用户访问的路径进行处理,获取请求路径的方法在上个任务中已经有所提及(request.path)
此外,这里还得介绍一下Tornado.web中的Application类其中的路由参数。不同的路由决定不同的大功能,而每个大功能中又有各自的小功能,举个例子,比如用户的注册,查询,修改是三个大功能,而修改中有着修改密码,修改头像这些小功能,路由就是用来实现大功能的不同请求路径,而get和post分发来实现不同的小功能的分发。
根据代码来理解会更加的清晰:
路由设置的代码(示例):
app = Application([
(r'/user/register/.*', RegisterHandler),
(r'/user/search/.*', SearchHandler),
(r'/user/change/.*', ChangeHandler)
])
其中Application中的一条数据就代表了一个大的功能,其中,
'/user/change/.*'
代表了功能的请求路径,后面的(.*)是正则表达式的用法,你可以把它理解成后面会跟接着对应的小功能的路径如:
'/user/change/change_pwd'或者'/user/change/change_username'
所以,可以这么理解,功能的分发就取决于请求路径的最后一段,当然也有别的情况,只需要设计不同的逻辑进行处理即可。
因此,在get和post请求中,我们需要对请求的路径进行处理,来找到用于分发的字段,从而调用对应的接口方法进行处理。
# 调用tornado库
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
import logging
# Meet处理器
class MeetHandler(RequestHandler):
# 日志方法
def log(self,msg): # msg为日志输出的信息
logger = logging.getLogger('logger')
logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
# 规定日志保存的路径
file_handler = logging.FileHandler('../test2/logs/log.txt')
file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info(msg)
# get方法重写
def get(self):
# 将路径以'/'来划分,组合成一个列表
path = self.request.path.split('/')
# 调用对应的接口方法是根据path列表中的最后一个字段
method = path[-1]
# 使用callable函数判断方法是否能够调用,getattr函数用来判断方法能否调用到
if callable(getattr(self, method)):
getattr(self, method)()
else:
self.write("404 not found")
# hello接口
def hello(self):
self.write("Hello, world")
# goodbye接口
def goodbye(self):
self.write("Goodbye, world")
# on_finish方法重写
def on_finish(self):
# 获取请求路径,请求方法,请求头,拼接成字符串,传入log方法,作为日志所保存的内容
msg = str(self.request.path) + str(self.request.method) + str(self.request.headers)
# 调用log方法
self.log(msg)
# 路由设置
app = Application([
(r"/meet/.*", MeetHandler)
])
# 程序启动
if __name__ == "__main__":
# 设置端口号
app.listen(8888)
IOLoop.current().start()
可以看到,我们在MeetHandler中写了hello和goodbye两个简单的接口,现在我们再次访问服务界面
访问http://127.0.0.1:8888/meet/hello
访问http://127.0.0.1:8888/meet/goodbye
这样便实现了请求的分发。