tornado 学习笔记7 RequestHandler功能分析
在第5部分讲到,构建一个tornado网站,必须包含一个或者多个handler,这些handler是RequestHandler的子类。每个请求都会被映射到handler中进行处理,处理后再将结果返回给客户端。所以,可以看到hanlder作为客户端请求跟业务服务逻辑间的桥梁,如果拿MVC的模式来类比的话,每个handler就相当于MVC中的Controller。
RequestHanlder作为所有hanlder的父类,我们看看他有哪些方法与接口,子类需要怎样继承?
7.1构造函数
定义:
def __init__(self, application, request, **kwargs):
参数:
application: Application对象
request: request请求对象
kwargs:其他参数,在hanlder映射配置时,可以设置。
处理过程:
super(RequestHandler, self).__init__() self.application = application
self.request = request
self._headers_written = False
self._finished = False
self._auto_finish = True
self._transforms = None # will be set in _execute
self._prepared_future = None
self.path_args = None
self.path_kwargs = None
self.ui = ObjectDict((n, self._ui_method(m)) for n, m in
application.ui_methods.items())
# UIModules are available as both `modules` and `_tt_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 `_tt_modules` to avoid
# possible conflicts.
self.ui["_tt_modules"] = _UIModuleNamespace(self,
application.ui_modules)
self.ui["modules"] = self.ui["_tt_modules"]
self.clear()
self.request.connection.set_close_callback(self.on_connection_close)
self.initialize(**kwargs)
- 对外部属性跟内部属性(带下划线)的赋值。
- 然后对ui的处理,这个暂时不做深入细读。
- self.clear() 调用clear方法,初始化一些属性。
- 设置请求连接关闭时的回调函数。
self.request.connection.set_close_callback(self.on_connection_close)
5. 调用初始化函数。
self.initialize(**kwargs)
这个被子类继承,针对每个hanlder实现自己的初始化过程。
入点函数
7.2 initialize方法
该方法被子类重写,实现初始化过程。参数的来源于配置Application时,传递的参数。举例如下:
# -*- coding: utf-8 -*-
from tornado.ioloop import IOLoop
from tornado.web import Application, RequestHandler __author__ = 'Administrator' class BookRequestHandler(RequestHandler):
def initialize(self, welcome):
self.welcome = welcome def get(self, *args, **kwargs):
print(self.welcome)
self.write(self.welcome) welcome = "**大学图书馆"
app = Application(handlers=[
(r"/book", BookRequestHandler, dict(welcome=welcome)),
]) def main():
app.listen(8888)
IOLoop.current().start() if __name__ == "__main__":
main()
将welcome初始化的值传递到BookRequestHandler的self.welcome属性中。当访问http://localhost:8888/book时,打印出welcome的值。
结果如下图:
7.3 prepare 、 on_finish方法
prepare方法用于当真正调用请求处理方法之前的初始化处理,比如get、post方法。而on_finish用于请求处理结束后的一些清理工作。这两个方法一个在处理前,一个在处理后,可以根据实际需要进行重写。比如用prepare方法做些初始化操作(比如赋值设置全局变量,比如打开I/O),而on_finish方法可以做一些清理对象占用的内存或者关闭数据库连接等等。举个例子,来证明他们的执行顺序。
class BookRequestHandler(RequestHandler):
def initialize(self, welcome,value2):
print("initialize method:initilize some variables....")
self.welcome = welcome
self.value2=value2 def get(self, *args, **kwargs):
#print(self.welcome + "\r\n" + "and value2 =" + self.value2)
print("get method: Processing get Method...........")
self.write(self.welcome + "\r\n" + "and value2 =" + self.value2) def set_default_headers(self):
self._headers.add("custom_header1", "custom_header1")
self._headers.add("custom_header2", "custom_header2") def prepare(self):
print("prepare method:initilize some variables....") def on_finish(self):
print("on_finish method:clear some memory or close database connection")
执行的结果如下:
所以得出执行的顺序为:
initialize > prepare > get > on_finish
如果有熟悉Java 的JUnit的话呢,prepare跟on_finish方法相当于before跟behind两个注解的功能。
获得输入的函数:
7.4 get_argument、get_arguments方法
返回给定参数的值,get_argument获得单个值,而get_arguments是针对参数存在多个值得情况下使用,返回多个值的列表。看一get_arguments方法的源代码,如下:
它的实现是调用了内部方法_get_arguments,注意传递的参数self.request.arguments,从request(HTTPServerRequest对象)的arguments属性中去查询给定名称的值。看看HTTPServerRequest源代码(位于tornado>httputil.py)对arguments的解释,如下截图:
大体意思就是说,这里存储的是客户端GET/POST方法提交上来的合并后的参数列表集合。也就是说RequestHanlder的get_arguments方法是能获得不管是Get还是POST得参数的值。举个GET提交参数的例子,
修改BookRequestHanlder的get方法。如下:
def get(self, *args, **kwargs):
#print(self.welcome + "\r\n" + "and value2 =" + self.value2)
print("get method: Processing get Method...........")
#self.write(self.welcome + "\r\n" + "and value2 =" + self.value2)
self.write("参数name的值为:" + self.get_argument("name", "liaofei"))
向游览器中打印出参数name的值,游览器中访问:http://localhost:8888/book?name=brain,结果如下图所示:
在举个POST方式提交参数的例子,在BookRequestHanlder 中新增POST方法,如下:
def post(self, *args, **kwargs):
print(self.request.arguments)
print("POS age:" + self.get_argument("age"))
self.write("POS age:" + self.get_argument("age"))
网上下载一个模拟工具进行POST数据提交,我找了很久用了,找到如下工具(很多工具不能用,这个稍微能用一下),
后台打印的结果为:,HTTPRequest 的arguments属性是一个字典。
提一个问题?如果URL中带有age查询参数,而post过去也有age参数,这时HTTPRequest 的arguments中age的值会是什么???测试一下便知。按照如下访问,
后台打印的结果为:,age的值是一个列表集合,将POST提交方式age参数值跟GET提交方式age参数值合并啦,而且是GET在前,POST再后。而get_arguments获得最后一个。
7.5 get_query_argument
、get_query_arguments方法
与get_argument、get_arguments功能类似,只是他仅仅是从URL查询参数中获取值。
7.6 get_body_argument
、get_body_arguments方法
与get_argument、get_arguments功能类似,只是他仅仅是从body中获取值。
再提一个问题?????get_query_argument、get _argument、get_body_argument的区别????测试一下便知。
按如下修改post方法,
def post(self, *args, **kwargs):
print(self.request.query_arguments)
print(self.request.arguments)
print(self.request.body_arguments)
print("POS age:" + self.get_argument("age"))
self.write("POS age:" + self.get_argument("age"))
按如下方式模拟访问:
后台打印的结果如下图:
所以得出结论就是,get _argument获取的值范围是get_query_argument与get_body_argument两者范围的合并。
输出响应函数:
7.7 clear方法
重置响应的所有的头部以及内容。
"""Resets all headers and content for this response."""
self._headers = httputil.HTTPHeaders({
"Server": "TornadoServer/%s" % tornado.version,
"Content-Type": "text/html; charset=UTF-8",
"Date": httputil.format_timestamp(time.time()),
})
self.set_default_headers()
self._write_buffer = []
self._status_code = 200
self._reason = httputil.responses[200]
处理过程
- 首先默认设置3个响应头部,分别是Server,Content_Type、Date.
- 调用set_default_headers 方法,实现自定义header的设置。
- 其他参数的默认设置。
7.9 set_default_headers方法
上面说了set_default_headers 方法是实现请求响应头部的自定义实现,被子类重写。举个例子。
在上面的BookRequestHandler中加入以下代码
def set_default_headers(self):
self._headers.add("custom_header1", "custom_header1")
self._headers.add("custom_header2", "custom_header2")
通过游览器访问http://localhost:8888/book,用firebug查询响应头。结果如下:
7.10 write方法
将给定的块输出到输出缓存中。如果给定的块是一个字典,就会将这个快当成是JSON并且将Content_Type设置成application/json返回给客户端。但是,如果你想用不同的Content_Type发送JSON,可以在调用write方法后再调用set_header方法进行设置。
注意,list 列表集合是不会转化成JSON的,原因是考虑到跨域的安全。所有的JSON输出都必须用字典包装。具体源码说明如下:
7.11 rend 方法
用给定的参数渲染模板。这个涉及到模板的概念,后续再学。
7.12 write_error方法
重写自定义错误页面的实现。
如果error是由没有捕获的异常(包括HTTPError)引起的,通过kwargs[|”exc_info”]能获取exc_info元组。实现代码如下:
举个例子实现一个自定义的错误页面,在BookRequestHandler中添加如下代码:
def write_error(self, status_code, **kwargs):
self.write("oh,my god!出错啦!!!!请联系系统管理员。\n")
self.write("呵呵,也没关系,我已经讲错误信息记录在日志中去了,系统管理员会看到的。\r\n")
if "exc_info" in kwargs:
self.write("错误信息为:\r\n")
for line in traceback.format_exception(*kwargs["exc_info"]):
self.write(line)
self.finish()
并将get方法修改成:
def get(self, *args, **kwargs):
# print(self.welcome + "\r\n" + "and value2 =" + self.value2)
print("get method: Processing get Method...........")
# self.write(self.welcome + "\r\n" + "and value2 =" + self.value2) # print(self.request.query_arguments)
# print(self.request.arguments)
# print(self.request.body_arguments)
# self.write("参数name的值为:" + self.get_argument("name", "liaofei")) print(1/0)
print(1/0)语句,人为地制造一个错误。在游览器中访问http://localhost:8888/book,得到如下结果,
就是使用了重写write_error中的方法实现。
Cookie相关函数
7.13
get_cookie
、set_cookie
获取与设置cookie的值。这个对熟悉web开发的人,一看就明白。就不多解释。
7.14
get_secure_cookie
、set_secure_cookie
获取与设置安全cookie的值。与7.13 相比加了一个单词secure(安全),就说明是为cookie安全加密解密的作用。这个方法涉及到
cookie_secret 的Application 设置选项。来举个列子说明他们之间的区别:
加入以下代码:
class CookieRequestHandler(RequestHandler):
def get(self, flag):
if flag == '0':
self.set_cookie("user", "liaofei")
elif flag == '1':
userCookie = self.get_cookie("user")
self.write(userCookie)
修改application的配置
settings = {
"debug":False,
"cookie_secret":"gagagaarwrslijwlrjoiajfoajgojowurwojrowjojgfoaguuuu9",
} app = Application(handlers=[
(r"/book", BookRequestHandler, dict(welcome=welcome, value2=value2)),
(r"/cookie/([0-1]+)", CookieRequestHandler),
], **settings)
(r"/cookie/([0-1]+)", CookieRequestHandler),
], **settings)
注意settings中设置了cookie_secret的值。
访问http://localhost:8888/cookie/0时,调用set_cookie
设置cookie中user的值为liaofei,并调用set_secure_cookie
设置cookie 中usersecure的值同样为liaofei。用firebug查看这个相同值得cookie(都是liaofei),发现在游览器客户端的值是不一样的,一个加密过,一个未加密。具体结果如下图:
tornado 学习笔记7 RequestHandler功能分析的更多相关文章
- Tornado学习笔记(一) helloword/多进程/启动参数
前言 当你觉得你过得很舒服的时候,你肯定没有在进步.所以我想学习新的东西,然后选择了Tornado.因为我觉得Tornado更匹配目前的我的综合素质. Tornado学习笔记系列主要参考<int ...
- tornado 学习笔记1 引言
从事软件开发这行业也快5年啦,其实从事的工作也不完全是软件开发,软件开发只是我工作中的一部分.其中包括课题研究.信息化方案设计.软件开发.信息系统监理.项目管理等工作,比较杂乱.开发的软件比较多,但是 ...
- tornado 学习笔记9 Tornado web 框架---模板(template)功能分析
Tornado模板系统是将模板编译成Python代码. 最基本的使用方式: t = template.Template("<html>{{ myv ...
- Tornado学习笔记(三) 请求方式/状态码
本章我们来学习 Tornado 支持的请求方式 请求方式 Tornado支持任何合法的HTTP请求(GET.POST.PUT.DELETE.HEAD.OPTIONS).你可以非常容易地定义上述任一种方 ...
- Tornado学习笔记(二) 路由/post/get传参
本章我们学习 Tornado 的路由传参等问题 路由 路由的匹配 Tornado的路由匹配采用的是正则匹配 一般情况下不需要多复杂的正则,正则的基本规则如下(站长之家) 举个例子 (r'/sum/(\ ...
- tornado学习笔记19 Tornado框架分析
19.1 Http服务器请求处理流程图 (1) 调用HTTPServer的bind方法,绑定Socket的监听端口号: (2) 调用HTTPServer的listen方法,初始化一个listen so ...
- tornado学习笔记11 Web应用中模板(Template)使用应用实践
上一篇中(Web应用中模板的工作流程分析),已经分析了模板的渲染流程,以及相关参数获取及设置原理.这篇主要讲述模板在实际应用案例. 11.1 需求 根据用户输入的两次密码,判断两次密码是否一致,并将判 ...
- tornado 学习笔记10 Web应用中模板(Template)的工作流程分析
第8,9节中,我们分析Tornado模板系统的语法.使用以及源代码中涉及到的相关类,而且对相关的源代码进行了分析.那么,在一个真正的Web应用程序中,模板到底是怎样使用?怎样被渲染? ...
- tornado 学习笔记8 模板以及UI
Tornado 包含一个简单.快速而且灵活的模板语言. Tornado同样可以使用任何其他的python模板语言,虽然没有集成这些模板语言进RequestHandler.ren ...
随机推荐
- 最新的jQuery插件和JavaScript库
每一个前端开发人员很清楚的重要性和功能的JavaScript库提供.它提供了一个简单的接口,用于构建快速动态的接口,而无需大量的代码. 谢谢你的超级从事jQuery开发者社区,人始终是创造新的和令人惊 ...
- GDI+ 笔记
1.GDI+模板 #include<windows.h> #include<GdiPlus.h> #include <time.h> #include <ma ...
- can't debug windows service in win7 64bit
if encount below error: Solution: run the command “vsdiag_regwcf.exe -i” as admin in C:\Program File ...
- 微信"流量红包"的玩法攻略 广东移动用户有福啦
前面我们说了广东移动联合微信正式推出流量红包业务,移动终于hold不住了,想要借此挽回一些些损失.只可惜,现在只是广东小范围测试,其他地区的用户暂时还没有这等福利.那么微信"流量红包&quo ...
- Windows 7个性化配置,关闭Win7动画效果,设置窗口背景为“ 豆绿色”
减少眼睛疲劳配色(豆绿色): RGB:, , ,颜色名称:#C7EDCC 1.任务栏设置 2.关闭Win7动画效果 控制面板 -> 轻松访问 -> 优化视频显示 3.去掉窗口阴影 右键单击 ...
- .htaccess 基础教程(一)
.htaccess是什么? .htaccess叫分布式配置文件,它提供了针对目录改变配置的方法——在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录.并且子目录中的 ...
- springmvc 表单提交
Spring MVC自带的表单标签比较简单,很多时候需要借助EL和JSTL来完成. 下面是一个比较简单的表单提交页面功能: 1.User model package com.my.controller ...
- 项目vue2.0仿外卖APP(一)
最近用vue.js做一个仿饿了么外卖APP的项目,现在也把流程啊什么的暂时先整理一下在这个博客上面. 当然,这个过程会有点长,不过确实能学到很多东西. 话不多说,马上开始吧. 1.项目介绍 选用当前最 ...
- 检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(转)
我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 500.23 - Internal Server Error 检测到在集成的托管管道模式下不适用的 ASP.N ...
- python——连接Oracle数据库
前言 Python自带的模块中有很多操纵文件的.我们可以把文件的数据读出来,经过处理还可以将数据写入文件中.但是对于数据的管理和分析来说,数据库还是专业一些.如果Python能和数据库结合在一起,那么 ...