Tornado是一个Python的服务器框架,自带socket,是一种异步非阻塞式服务器,速度非常快,每秒可以处理数千以上的连接,对于实时Web服务来说是一个非常理想的Web框架。
Tornado性能强悍,是一个较为原始的框架,诸多内容需要自己去处理。当然,随着项目越来越大,框架能够提供的功能占比越来越小,更多的内容需要团队自己去实现,而大项目往往需要性能的保证,这时候 Tornado 就是比较好的选择。
主要特点:原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架
优点:1. 少而精(轻量级框架)
2. 注重性能优越,速度快
3. 解决高并发(请求处理是基于回调的非阻塞调用)
4. 异步非阻塞
5. websockets 长连接
6. 内嵌了HTTP服务器
7. 单线程的异步网络程序,默认启动时根据CPU数量运行多个实例;利用CPU多核的优势
8. 自定义模块
缺点:模板和数据库部分有很多第三方的模块可供选择,这样不利于封装为一个功能模块
Flask是一个微型的Python开发的Web框架,整个框架只有一个文件。号称 Python 代码写得最好的项目之一。Flask 的灵活性很强,可以自由选择自己的数据库交互组件。
主要特点:小而轻,原生组件几乎为0。
优点:1. 简单,Flask的路由以及路由函数由修饰器设定,开发人员不需要借助其他文件匹配;
2. 配置灵活,有多种方法配置,不同环境的配置也非常方便;
- 环境部署简单,Flask运行不需要借助其他任何软件,只需要安装了Python的IDE,在命令行运行即可。只需要在Python中导入相应包即可满足所有需求;
4. 入门简单,通过官方指南便可以清楚的了解Flask的运行流程;
5. 低耦合,Flask可以兼容多种数据库、模板。
缺点:对于大型网站开发,需要设计路由映射的规则,否则导致代码混乱
一、Tornado框架的基本组成
tornado功能概览:
socket:有(异步非阻塞、支持WebScoket)
路由系统:有
视图函数:有
静态文件:有
ORM操作:无
模板语言:有
simple_tag:有,uimethod,uimodule
cokies:有
session:无
csrf:有
xss:有
其他:无
import tornado.httpserver # 用来解决web服务器的http协议问题,提供了不少属性方法,实现客户端和服务器端的互通, Tornado的非阻塞、单线程的特点在这个模块中体现 import tornado.ioloop # 实现非阻塞socket循环 import tornado.options # 命令行解析模块 import tornado.web # 提供了一个简单的Web框架与异步功能 from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class IndexHandler(tornado.web.RequestHandler): # 定义 “请求-处理程序“ 类, tornado.web.RequestHandler 是专门用于完成请求处理程序的 def get(self): greeting = self.get_argument('greeting', 'Hello') # get_argument()是一个方法, 实列化之后的self对应的就是tornado.web.RequestHandler, 当'greeting'为空时,返回'hello', http://localhost:8000/?greeting=Qiwsir,就可以实现对greeting的赋值 self.write(greeting + ', welcome you') # 打印 if __name__ == "__main__": tornado.options.parse_command_line() # 执行tornado的解析命令行 app = tornado.web.Application(handlers=[(r"/", IndexHandler)]) # 实列化, 在一般情况下,handlers是不能为空的, 因为Application类通过这个参数的值处理所得到的请求 http_server = tornado.httpserver.HTTPServer(app) # HTTPServer是一个单线程非阻塞HTTP服务器, 执行HTTPServer一般要回调Application对象,并提供发送响应的接口, 也就是下面的内容是跟随上面语句的 http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() # 表示可以接收来自HTTP的请求了
二、Tornado自带功能
- Tornado执行流程
第一步:执行脚本,监听 8888 端口
第二步:浏览器客户端访问 /index --> http://127.0.0.1:8888/index/
第三步:服务器接受请求,并交由对应的类处理该请求
第四步:类接受到请求之后,根据请求方式(post / get / delete/put)的不同调用并执行相应的方法
第五步:方法返回值的字符串内容发送浏览器
浏览器访问: http://127.0.0.1:8888/index/ 输出:hellow ,world
浏览器访问: http://127.0.0.1:8888/login/ 输出:hellow ,world, hello, hello, psw
- 路由系统
2.1 动态路由
动态URL传参:
浏览器访问:http://127.0.0.1:8888/login/123 输出:hellow ,world123
tornado中传递参数的几种方式:
方法一 :tornado路由可以使用正则表达式中的子表达式传递url参数。例如:(r"/login/(d+)",Login) 匹配以后,tornado会将字符串()中匹配到的内容,作为参数传递到Login中去,因此我们在Login中定义get方法时增加参数。
方法二 :通过 self.get_argument()
tornado的get和post提交的参数都可以通过self.get_argument()获得,只需要填写第一个参数值即可。一次性获取所有的参数方法:self.get_arguments()
方法三 :self.request.body
tornado的参数存储在self.request.body内,通过JSON以后就可以直接取值。
2.2 域名匹配
可以进行域名绑定,因为是一串正则,所以支持多域名。
2.3 反向生成url
- 视图
tornado的视图才有CBV模式,URL匹配成功之后,视图执行顺序为 initialize 、prepare、get/post/put/delete、finish;
3.1 请求相关
self.get_body_argument('user') :获取POST请求携带的参数
self.get_body_arguments('user_list') :获取POST请求参数列表(如chebox标签和select多选)
self.request.body.decode('utf-8'):获取json数据
self.get_query_argument('user') :获取GET请求携带的参数
self.get_query_arguments('user_list') :获取GET请求参数列表(如chebox标签和select多选)
self.get_argument('user') :获取GET和POST请求携带的参数
self.get_arguments('user_list'):获取GET和POST请求参数列表(如chebox标签和select多选)
注:以上取值方式如果取不到值就会报错,可以设置取不到值就取None;(例如 self.get_argument('user',None))
3.2 响应相关
self.write() : 响应字符串
self.render(): 响应页面
self.redirect(): 页面跳转
- 引入静态文件
通过static_url()方法引入静态文件的好处:
1、使用static_url()可以不用考虑静态文件修改之后造成引用失效的情况;
2、还会生成静态文件url会有一个v=...的参数,这是tornado根据静态文件MD5之后的值,如果后台的静态文件修改,这个值就会变化,前端就会重新向后台请求静态文件,保证页面实时更新,不引用浏览器缓存。
上下文对象:
如果模板语言中声明了变量,上下文对象必须对应传值,如果没有就设置为空,否则会报错;
- Cokies
5.1 设置Cokies
获取cokies:self.get_cookie('username')
设置在用户不断刷新页面的情况,cookies不过期;
5.2 Tornado加密cokie
配置加密规则使用的字符串
设置加密的cokies:self.set_secure_cookie('username',user,expires=v)
获取加密的cokies:self.get_secure_cookie('username')
设置在用户不断刷新页面的情况,SecureCookies不过期;
5.3 @authenticated 装饰器
执行 self.curent_user,有值就登录用户,无就去执行get_curent_user方法,get_curent_user没有返回用户信息,会记录当前url更加配置文件跳转到登录页面;
Tornado使用表单和模板:tornado模板self.render和模板变量传递:
Tornado可以运用future对象,进行异步处理:
tornado解决异步请求就是利用future对象。future对象中设定默认参数result=None,如果在某一时刻future的result中被设定值了,那么它就会自动执行回调函数,实际上这种执行回调函数的功能就是所谓的异步,不需要服务器等待,自己自动执行完后会进行回调。
一个最小的Flask应用如下:
from flask import Flask app = Flask(__name__) @app.route('/')def hello_world(): return 'Hello, World!'
- 首先我们导入了 Flask 类。 该类的实例将会成为我们的 WSGI 应用。
- 接着我们创建一个该类的实例。第一个参数是应用模块或者包的名称。如果你使用 一个单一模块(就像本例),那么应当使用 __name__ ,因为名称会根据这个 模块是按应用方式使用还是作为一个模块导入而发生变化(可能是 ‘__main__’ , 也可能是实际导入的名称)。这个参数是必需的,这样 Flask 才能知道在哪里可以 找到模板和静态文件等东西。更多内容详见 Flask 文档。
- 然后我们使用 route() 装饰器来告诉 Flask 触发函数的 URL 。
- 函数名称被用于生成相关联的 URL 。函数最后返回需要在用户浏览器中显示的信息。
1、路由
使用route()装饰器来把函数绑定到URL:
1 @app.route('/post/<int:post_id>') 2 3 def show_post(post_id): 4 5 return 'Post %d' % post_id
- /…/里面的内容是URL的路径名,<…>里面的内容是接收的参数,默认为string类型。
- 转换器类型:
2、HTTP
Web应用使用不同的HTTP方法处理URL。当你使用Flask时,应当熟悉 HTTP方法。缺省情况下,一个路由只回应GET请求。可以使用route()装饰器的methods参数来处理不同的HTTP方法:
1 from flask import request 2 3 @app.route('/login', methods=['GET', 'POST']) 4 5 def login(): 6 7 if request.method == 'POST': 8 9 return do_the_login() 10 11 else: 12 13 return show_the_login_form()
3、渲染模板
使用render_template('模板名','变量')方法可以渲染模板,只需要提供模板名称和需要作为参数传递给模板的变量就可以了
from flask import render_template @app.route('/hello/<name>') def hello(name=None): return render_template('hello.html', name=name)
4、请求对象
request通过使用method属性可以操作当前请求方法,通过使用form属性处理表单数据。
5、文件上传
在HTML表单中设置enctype="multipart/form-data" 属性。已上传的文件被储存在内存或文件系统的临时位置。你可以通过请求对象files属性来访问上传的文件。每个上传的文件都储存在这个 字典型属性中。这个属性基本和标准 Python file对象一样,另外多出一个 用于把上传文件保存到服务器的文件系统中的save()方法。
from flask import request @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': f = request.files['the_file'] f.save('/var/www/uploads/uploaded_file.txt')
如果想要知道文件上传之前其在客户端系统中的名称,可以使用filename属性。但是请牢记这个值是可以伪造的,永远不要信任这个值。如果想要把客户端的文件名作为服务器上的文件名,可以通过Werkzeu提供的secure_filename() 函数:
from flask import request from werkzeug.utils import secure_filename @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': f = request.files['the_file'] f.save('/var/www/uploads/' + secure_filename(f.filename))
6、Cookies
要访问cookies,可以使用cookies属性。可以使用响应对象的set_cookie方法来设置cookies。请求对象的cookies属性是一个包含了客户端传输的所有cookies的字典。
读取cookies:
from flask import request @app.route('/') def index(): username = request.cookies.get('username')
储存cookies:
from flask import make_response @app.route('/') def index(): resp = make_response(render_template(...)) resp.set_cookie('username', 'the username') return resp
7、重定向和错误
使用redirect()函数可以重定向。使用abort()可以更早退出请求,并返回错误代码:
from flask import abort, redirect, url_for @app.route('/') def index(): return redirect(url_for('login')) @app.route('/login') def login(): abort(401) this_is_never_executed()
上例实际上是没有意义的,它让一个用户从索引页重定向到一个无法访问的页面(401表示禁止访问)。但是上例可以说明重定向和出错跳出是如何工作的。缺省情况下每种出错代码都会对应显示一个黑白的出错页面。使用 errorhandler()装饰器可以定制出错页面:
from flask import render_template @app.errorhandler(404) def page_not_found(error): return render_template('page_not_found.html'), 404
8、响应
- 如果视图返回的是一个响应对象,那么就直接返回它。
- 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的响应对象。
- 如果返回的是一个字典,那么调用 jsonify 创建一个响应对象。
- 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由 (response, status) 、 (response, headers) 或者 (response, status, headers) 组成。 status 的值会重载状态代码, headers 是一个由额外头部值组成的列表 或字典。
- 如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。