Tornado
Tornado概述
Python的Web框架种类繁多(比Python语言的关键字还要多),但在众多优秀的Web框架中,Tornado框架最适合用来开发需要处理长连接和应对高并发的Web应用。Tornado框架在设计之初就考虑到性能问题,它可以处理大量的并发连接,更轻松的应对C10K(万级并发)问题,是非常理想的实时通信Web框架。
Tornado框架源于FriendFeed网站,在FriendFeed网站被Facebook收购之后得以开源,正式发布的日期是2009年9月10日。Tornado能让你能够快速开发高速的Web应用,如果你想编写一个可扩展的社交应用、实时分析引擎,或RESTful API,那么Tornado框架就是很好的选择。Tornado其实不仅仅是一个Web开发的框架,它还是一个高性能的事件驱动网络访问引擎,内置了高性能的HTTP服务器和客户端(支持同步和异步请求),同时还对WebSocket提供了完美的支持。
了解和学习Tornado最好的资料就是它的官方文档,在tornadoweb.org上面有很多不错的例子,你也可以在Github上找到Tornado的源代码和历史版本。
1、Tornado项目创建
1.1 创建一个新的Tornado虚拟环境并激活
mkvirtualenv tornadoenv -p /usr/bin/python3
1.2.安装Tornado
pip install tornado
如果不是做项目,也可以不用安装新的虚拟环境,在以前的虚拟环境中直接安装Tornado
1.3 新建一个helloTornado项目
1.3.1 环境变量的选择
创建项目的时候,选择一般项目
如果不是要迁移的项目,可以选一般的环境变量
也可选Tornado环境变量
1.3.2 新建一个helloworld.py文件
import tornado.web
import tornado.ioloop
#类视图
class MainHandler(tornado.web.RequestHandler):
#处理get类型的请求
def get(self):
# 把内容写到HttpResponse里面,相当于Django的HttpResponse
self.write('hello world')
# 处理post类型的请求
def post(self):
self.write('this is post')
# 创建一个app,用它来启动我们的服务器
def make_app():
return tornado.web.Application(handlers=[
# 第一个参数是路由(正则匹配),第二个参数是类视图,
# 当浏览器访问http://ffad/dfjshd/index/让MainHandler去处理
(r'/index',MainHandler),
])
if __name__=='__main__':
# 创建一个app
app=make_app()
# 绑定监听端口
app.listen(8888)
# 开启web应用程序
tornado.ioloop.IOLoop.current().start()
运行这个程序,右键运行run,也可以在底部的Terminal栏输入命令
python helloworld.py
在浏览器中输入地址
在上面的例子中,代码helloworld.py通过定义一个继承自
RequestHandler
的类(MainHandler
)来处理用户请求,当请求到达时,Tornado会实例化这个类(创建MainHandler
对象),并调用与HTTP请求方法(GET、POST等)对应的方法,显然上面的MainHandler
只能处理GET请求,在收到GET请求时,它会将一段HTML的内容写入到HTTP响应中。main
函数的第1行代码创建了Tornado框架中Application
类的实例,它代表了我们的Web应用,而创建该实例最为重要的参数就是handlers
,该参数告知Application
对象,当收到一个请求时应该通过哪个类的对象来处理这个请求。在上面的例子中,当通过HTTP的GET请求访问站点根路径时,就会调用MainHandler
的get
方法。main
函数的第2行代码通过Application
对象的listen
方法指定了监听HTTP请求的端口。main
函数的第3行代码用于获取Tornado框架的IOLoop
实例并启动它,该实例代表一个条件触发的I/O循环,用于持续的接收来自于客户端的请求。
扩展:在Python 3中,
IOLoop
实例的本质就是asyncio
的事件循环,该事件循环在非Windows系统中就是SelectorEventLoop
对象,它基于selectors
模块(高级I/O复用模块),会使用当前操作系统最高效的I/O复用选择器,例如在Linux环境下它使用EpollSelector
,而在macOS和BSD环境下它使用的是KqueueSelector
;在Python 2中,IOLoop
直接使用select
模块(低级I/O复用模块)的epoll
或kqueue
函数,如果这两种方式都不可用,则调用select
函数实现多路I/O复用。当然,如果要支持高并发,你的系统最好能够支持epoll或者kqueue这两种多路I/O复用方式中的一种。
1.3.3 通过命令行参数来指定Web应用的监听端口
新建一个tornadoarfs.py文件
import tornado.web
import tornado.ioloop
from tornado.options import define,options,parse_command_line
# define 定义端口的选项 options 创建这些选项 parse_command_line 解释命令行
# 定义端口号port1,默认是8080,类型int
define('port1',default=8080,type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write('hello')
def main():
app=tornado.web.Application(handlers=[
(r'/',IndexHandler),
])
# 使用定义的端口号port1
app.listen(options.port1)
#这里注释8888端口
# app.listen(8888)
tornado.ioloop.IOLoop.current().start()
if __name__=='__main__':
main()
在底部的Terminal栏输入命令
python tornadoargs.py --prot1=8080
在浏览器中输入地址
如果不把8888端口注释,这两个端口都能访问
如果在def main 函数下的第一行添加一行代码
# 解析输入的参数
parse_command_line()
在底部的Terminal栏输入命令,把端口号port1改一下
python tornadoargs.py --port1=8000
然后浏览器中输入8080就不能显示页面内容了,这时的端口号是8000;如果8888端口没有注释的话,这个端口还是能用的
可以在终端输入命令
netstat -antp
查看一下监听的进程
ps -aux|grep python
每次做出修改,都要先重启一下项目刷新一下,才能查看到效果
2、url解析
上面我们曾经提到过创建Application
实例时需要指定handlers
参数,这个参数非常重要,它应该是一个元组的列表,元组中的第一个元素是正则表达式,它用于匹配用户请求的资源路径;第二个元素是RequestHandler
的子类。在刚才的例子中,我们只在handlers
列表中放置了一个元组,事实上我们可以放置多个元组来匹配不同的请求(资源路径),而且可以使用正则表达式的捕获组来获取匹配的内容并将其作为参数传入到get
、post
这些方法中。
2.1 url传参数 (get)
2.1.1 一个参数
写一个名字name的类试图
class NameHandler(tornado.web.RequestHandler):
def get(self,name):
print(name)
self.write('you name is :%s' %name)
添加一条url,这些参数是通过正则的方式去匹配
重启一下服务器,可以不输入端口号,这样就是使用定义的默认端口8080
python tornadoargs.py
去浏览器地址栏输入url
2.1.2 多个参数
写一个时间DaysHandler的类试图
class DaysHandler(tornado.web.RequestHandler):
def get(self,year,month,day):
print(year,month,day)
self.write('<h3>%s-%s-%s</h3>' %(year,month,day))
添加一条url
(r'/day/(\d+)/(\d+)/(\d+)/',DaysHandler),
#限制一下位数,如果输入的url不符合正则,会弹出 404 not found
(r'/day/(\d{4})/(\d{2})/(\d{2})/',DaysHandler),
#给参数取名 名称一定要和类试图里的名称一致,类试图中参数的顺序不做要求
(r'/day/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/',DaysHandler),
重启一下服务器,去浏览器地址栏输入url
从浏览器地址栏输入的参数,获取的类型都是str类型
2.2 url传参数 (post)
2.2.1 传入post请求 输出 this is post
在终端输入命令
curl -X POST 127.0.0.1:8080
2.2.2 post一个参数name
修改一下类视图
class NameHandler(tornado.web.RequestHandler):
def get(self,name):
print(name)
self.write('you name is :%s' %name)
def post(self,name):
print(name)
self.write('name post: %s' %name)
去终端传入一个参数name
2.3 url传参数 (put)
2.4使用软件方式提交参数
软件Postman
链接:https://pan.baidu.com/s/1GQ3bHzWAN1agj3yurtqM8Q
提取码:dhz1
先在虚拟机终端输入命令 ifconfig 查看ip
2.5 模板和响应
2.5.1 模板文件
2.5.1.1 平级创建模板
新建一个index.html文件
写一个类试图
class RenderHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
写一下url
(r'/temp/',RenderHandler),#模板
浏览器地址栏输入
2.5.1.2 创建templates文件夹方式创建模板
在templates文件夹内创建index.html文件
只需要修改一下类试图,在浏览器地址栏中输入同样的url一样可以进入index.html首页
class RenderHandler(tornado.web.RequestHandler):
def get(self):
self.render('templates/index.html')
2.5.1.3 给templates文件夹配置路径方式创建模板
先写一下项目路径
配置templates文件夹的路径
这个时候还需再修改一下类试图
浏览器地址栏中刷新一下,依旧是相同的url,可以跳转到index.html首页
顺带一提,templates文件夹可以自行给它定义成模板文件夹,然后有一些报红但不影响运行效果的代码会取消报红(可以有,但没什么必要)
2.5.2 静态文件
新建一个static文件夹,写上css样式(pycharm不支持Tornado直接创建css文件,选择创建普通文件 第一个选项 file ,新建时加上.css后缀);
给static文件夹配置路径
index.html文件引入index.css文件的方式有两种,后面双大括号是Tornado特有的方式,这里报红并没有关系
查看一下浏览器
2.5.3 url参数的传递
2.5.3.1 在类试图中加入参数name
传到模板index.html上
查看一下浏览器
2.5.3.2 获取参数
获取get类型的参数
在浏览器的地址栏中输入参数
查看打印的内容
获取post,put类型的参数
2.5.4 操作状态码和响应头
状态码
响应头 500开头
和输出相关的方法
查看一下浏览器,首页和其他内容就没了