Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。
我们现在所知道的Tornado是基于Bret Taylor和其他人员为FriendFeed所开发的网络服务框架,当FriendFeed被Facebook收购后得以开源。不同于那些最多只能达到10,000个并发连接的传统网络服务器,Tornado在设计之初就考虑到了性能因素,旨在解决C10K问题,这样的设计使得其成为一个拥有非常高性能的框架。此外,它还拥有处理安全性、用户验证、社交网络以及与外部服务(如数据库和网站API)进行异步交互的工具。
1)pip install tornado 2)源码安装:https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
基本上所有的Web框架都是以下的流程(以Tornado为例):
准备阶段
加载配置文件
加载路由映射 application = tornado.web.Application([(r"/index", MainHandler),])
创建socket
循环阶段
类似socket Server不断的循环监听文件句柄,当有请求过来的时候,根据用户的请求方法来来判断是什么请求,在通过反射来执行相应的函数或类
流程:
第一步:执行脚本,监听 8888 端口 第二步:浏览器客户端访问 /index --> http://127.0.0.1:8888/index 第三步:服务器接受请求,并交由对应的类处理该请求 第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法 第五步:方法返回值的字符串内容发送浏览器
application = tornado.web.Application([(r"/index", MainHandler),])
内部在执行的时候执行了两个方法__init__方法和self.add_handlers(".*$", handlers)方法
add_handlers默认传输的".*$" 就是www,他内部生成的路由映射的时候相当于(二级域名的方式)下图:
如果匹配的是shuaige他会去"shuaige"里去找对应关系,如果没有匹配默认就去.*,他这个就类似Django中的URL分类
application = tornado.web.Application([ (r"/index", MainHandler), ]) application.add_handlers("shuaige.com",([ (r"/index", MainHandler), ]) )
路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。
#!/usr/bin/env python #-*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") class Shuaige(tornado.web.RedirectHandler): def get(self): self.write("This is shuaige web site,hello!") application = tornado.web.Application([ (r"/index", MainHandler), ]) application.add_handlers("kongweiqi.com",([ (r"/index", kongweiqi), ]) ) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
路由系统可以分为几类:
静态路由
动态路由
请求方法路由
二级路由
@root.route(‘/hello/‘) def index(): return template(‘<b>Hello {{name}}</b>!‘, name="weiqi")
并且可以绑定多个装饰器如代码(当你访问hello的时候回执行下面的函数,当你访问index的时候也会执行下面的index函数)
@root.route(‘/index/‘) @root.route(‘/hello/‘) def index(): #return "Hello World" return template(‘<b style="background-color:red">Hello {{name}}</b>!‘, name="Tim") root.run(host=‘localhost‘, port=8080)
@root.route(‘/wiki/<pagename>‘) def callback(pagename): ... #当请求过来之后@root.route(‘/wiki/<pagename>‘) 这个pagename值就会自动把值赋值给def callback(pagename):的参数
@root.route(‘/wiki/<pagename>‘) def callback(pagename): ... @root.route(‘/object/<id:int>‘) def callback(id): ... @root.route(‘/show/<name:re:[a-z]+>‘) def callback(name): ... @root.route(‘/static/<path:path>‘) def callback(path): return static_file(path, root=‘static‘)
在http访问请求中有很多请求方法比如get、post、delete等
如果使用了@root.get就表示这个装饰器下的函数只接收get请求!
@root.route(‘/hello/‘, method=‘POST‘) def index(): ... @root.get(‘/hello/‘) def index(): ... @root.post(‘/hello/‘) def index(): ... @root.put(‘/hello/‘) def index(): ... @root.delete(‘/hello/‘) def index(): ...
多个APP把不同app下的请求转发到不同的app下面进行处理
#!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle from bottle import static_file root = Bottle() @root.route(‘/hello/‘) def index(): return template(‘<b>Root {{name}}</b>!‘, name="Alex") from framwork_bottle import app01 from framwork_bottle import app02 root.mount(‘app01‘, app01.app01) root.mount(‘app02‘, app02.app02) root.run(host=‘localhost‘, port=8888)
#!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle app01 = Bottle() @app01.route(‘/hello/‘, method=‘GET‘) def index(): return template(‘<b>App01</b>!‘
#!/usr/bin/env python # -*- coding:utf-8 -*- from bottle import template, Bottle app02 = Bottle() @app02.route(‘/hello/‘, method=‘GET‘) def index(): return template(‘<b>App02</b>!‘)
Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
Tornado 的模板支持“控制语句”和“表达语句”,
控制语句是使用 {%
和 %}
包起来的 例如 {% if len(items) > 2 %};
表达语句是使用 {{
和 }}
包起来的,例如 {{ items[0] }};
控制语句和对应的 Python 语句的格式基本完全相同。我们支持 if
、for
、while
和 try
,
这些语句逻辑结束的位置需要用 {% end %}
做标记。还通过 extends
和 block
语句实现了模板继承。这些在 template
模块 的代码文档中有着详细的描述。
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render(‘home/index.html‘) settings = { ‘template_path‘: ‘template‘, } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(80) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>老男孩</title> <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> {% block CSS %}{% end %} </head> <body> <div class="pg-header"> </div> {% block RenderBody %}{% end %} <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> {% block JavaScript %}{% end %} </body> </html> layout.html
{% extends ‘layout.html‘%} {% block CSS %} <link href="{{static_url("css/index.css")}}" rel="stylesheet" /> {% end %} {% block RenderBody %} <h1>Index</h1> <ul> {% for item in li %} <li>{{item}}</li> {% end %} </ul> {% end %} {% block JavaScript %} {% end %} index.html
{% extends ‘layout.html‘%} {% block CSS %} <link href="{{static_url("css/index.css")}}" rel="stylesheet" /> {% end %} {% block RenderBody %} <h1>Index</h1> <ul> {% for item in li %} <li>{{item}}</li> {% end %} </ul> {% end %} {% block JavaScript %} {% end %}
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>1、单值</h1> {{name}} #应用后端返回的数据 <h1>2、单行Python代码</h1> % s1 = "hello" {{ s1 }} #‘%s1 这里设置一个变量,我们可以在html调用和python类似‘ <h1>3、Python代码块</h1> <% # python块代码 name = name.title().strip() if name == "shuaige": name="luotianshuai" %> <h1>4、Python、Html混合</h1> % if True: <span>{{name}}</span> % end <ul> % for item in name: <li>{{item}}</li> % end </ul> </body> </html>
include(sub_template, **variables)
# 导入其他模板文件 % include(‘header.tpl‘, title=‘Page Title‘) Page Content % include(‘footer.tpl‘)
rebase(name, **variables)
<html> <head> <title>{{title or ‘No title‘}}</title> </head> <body> {{!base}} </body> </html>
导入母版
% rebase(‘base.tpl‘, title=‘Page Title‘) <p>Page Content ...</p>
defined(name) #检查当前变量是否已经被定义,已定义True,未定义False get(name, default=None) #获取某个变量的值,不存在时可设置默认值 setdefault(name, default) #如果变量不存在时,为变量设置默认值
在模板中默认提供了一些函数、字段、类以供模板使用:
escape
: tornado.escape.xhtml_escape
的別名
xhtml_escape
: tornado.escape.xhtml_escape
的別名
url_escape
: tornado.escape.url_escape
的別名
json_encode
: tornado.escape.json_encode
的別名
squeeze
: tornado.escape.squeeze
的別名
linkify
: tornado.escape.linkify
的別名
datetime
: Python 的 datetime
模组
handler
: 当前的 RequestHandler
对象
request
: handler.request
的別名
current_user
: handler.current_user
的別名
locale
: handler.locale
的別名
_
: handler.locale.translate
的別名
static_url
: for handler.static_url
的別名
xsrf_form_html
: handler.xsrf_form_html
的別名
Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule,我们也可以自定义从而实现类似于Django的simple_tag的功能。
1、定义
def tab(self): return ‘UIMethod‘
#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.web import UIModule from tornado import escape class custom(UIModule): def render(self, *args, **kwargs): return escape.xhtml_escape(‘<h1>wupeiqi</h1>‘) #return escape.xhtml_escape(‘<h1>wupeiqi</h1>‘)
2、注册
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from tornado.escape import linkify import uimodules as md import uimethods as mt class MainHandler(tornado.web.RequestHandler): def get(self): self.render(‘index.html‘) settings = { ‘template_path‘: ‘template‘, ‘static_path‘: ‘static‘, ‘static_url_prefix‘: ‘/static/‘, ‘ui_methods‘: mt, ‘ui_modules‘: md, } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8009) tornado.ioloop.IOLoop.instance().start()
3、使用
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url("commons.css")}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> {% module custom(123) %} {{ tab() }} </body>
由于Web框架就是用来【接收用户请求】-> 【处理用户请求】-> 【响应相关内容】,对于具体如何处理用户请求,开发人员根据用户请求来进行处理,而对于接收用户请求和相应相关的内容均交给框架本身来处理,其处理完成之后将产出交给开发人员和用户。
【接收用户请求】
当框架接收到用户请求之后,将请求信息封装在Bottle的request中,以供开发人员使用
【响应相关内容】
当开发人员的代码处理完用户请求之后,会将其执行内容相应给用户,相应的内容会封装在Bottle的response中,然后再由框架将内容返回给用户
所以,公共组件本质其实就是为开发人员提供接口,使其能够获取用户信息并配置响应内容。
request.headers #请求头信息,可以通过请求头信息来获取相关客户端的信息 request.query #get请求信息,如果用户访问时这样的:http://127.0.0.1:8000/?page=123就必须使用request.query 使用GET方法是无法取到信息的 request.forms #post请求信息 request.files #上传文件信息 request.params #get和post请求信息,他是GET和POST的总和,其实他内部调用了request.get request.forms request.GET #get请求信息 request.POST #post和上传信息,上传文件信息,和post信息 request.cookies #cookie信息 request.environ #环境相关相关,如果上面的这些请求信息没有满足你的需求,就在这里找!
对于静态文件,可以配置静态文件的目录和前段使用时的前缀,并且Tornaodo还支持静态文件缓存。
静态文件缓存:
<link href="{{static_url(‘css/index.css‘)}}" rel="stylesheet" /> """ 在Tornado中写成变量形式的主要是为了以后扩展方便,还有一个缓存的功能 """
原理:
拿一个静态文件来说:/static/commons.js如果用Tornado封装后,类似于给他加了一个版本号/static/commons.js?v=sldkfjsldf123
当客户端访问过来的时候会携带这个值,如果发现没变客户端缓存的静态文件直接渲染就行了,不必再在服务器上下载一下静态文件了。
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render(‘index.html‘) settings = { ‘template_path‘: ‘template‘, ‘static_path‘: ‘static‘, ‘static_url_prefix‘: ‘/static/‘, } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url(‘commons.css‘)}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> </body> </html>
Tornado静态文件实现缓存
def get_content_version(cls, abspath): """Returns a version string for the resource at the given path. This class method may be overridden by subclasses. The default implementation is a hash of the file‘s contents. .. versionadded:: 3.1 """ data = cls.get_content(abspath) hasher = hashlib.md5() if isinstance(data, bytes): hasher.update(data) else: for chunk in data: hasher.update(chunk) return hasher.hexdigest()
跨站脚本攻击
恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。
跨站伪造请求(Cross-site request forgery)
settings = { "xsrf_cookies": True, } application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], **settings)
<form action="/new_message" method="post"> {{ xsrf_form_html() }} <input type="text" name="message"/> <input type="submit" value="Post"/> </form>
function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } jQuery.postJSON = function(url, args, callback) { args._xsrf = getCookie("_xsrf"); $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST", success: function(response) { callback(eval("(" + response + ")")); }}); }; Ajax使用
注:Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求
Tornado中可以对cookie进行操作,并且还可以对cookie进行签名以放置伪造。
a、基本操作
class MainHandler(tornado.web.RequestHandler): def get(self): if not self.get_cookie("mycookie"): self.set_cookie("mycookie", "myvalue") self.write("Your cookie was not set yet!") else: self.write("Your cookie was set!")
b、签名
Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:
签名Cookie的本质是:
写cookie过程:
将值进行base64加密
对除值以外的内容进行签名,哈希算法(无法逆向解析)
拼接 签名 + 加密值
读cookie过程:
读取 签名 + 加密值
对签名进行验证
base64解密,获取值内容
除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。
操作session
区别:cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from hashlib import sha1 import os, time session_container = {} create_session_id = lambda: sha1(‘%s%s‘ % (os.urandom(16), time.time())).hexdigest() class Session(object): session_id = "__sessionId__" def __init__(self, request): #当你请求过来的时候,我先去get_cookie看看有没有cookie!目的是看看有没有Cookie如果有的话就不生成了,没有就生成! session_value = request.get_cookie(Session.session_id) #如果没有Cookie生成Cookie[创建随机字符串] if not session_value: self._id = create_session_id() else: #如果有直接将客户端的随机字符串设置给_id这个字段,随机字符串封装到self._id里了 self._id = session_value #在给它设置一下 request.set_cookie(Session.session_id, self._id) def __getitem__(self, key): ret = None try: ret = session_container[self._id][key] except Exception,e: pass return ret def __setitem__(self, key, value): #判断是否有这个随机字符串 if session_container.has_key(self._id): session_container[self._id][key] = value else: #如果没有就生成一个字典 ‘‘‘ 类似:随机字符串:{‘IS_LOGIN‘:‘True‘} ‘‘‘ session_container[self._id] = {key: value} def __delitem__(self, key): del session_container[self._id][key] class BaseHandler(tornado.web.RequestHandler): def initialize(self): ‘‘‘ 这里initialize的self是谁? obj = LoginHandler() obj.initialize() ==>这里LoginHandler这个类里没有initialize这个方法,在他父类里有 所以initialize得self就是LoginHandler的对象 ‘‘‘ self.my_session = Session(self) #执行Session的构造方法并且把LoginHandler的对象传过去 ‘‘‘ 这个self.my_session = Session() 看这个例子: self.xxx = ‘123‘ 在这里创建一个对象,在LoginHandler中是否可以通过self.xxx去访问123这个值? 可以,因为self.xxx 是在get之前执行的,他们俩的对象都是LoginHandler对象 ‘‘‘ class MainHandler(BaseHandler): def get(self): ret = self.my_session[‘is_login‘] if ret: self.write(‘index‘) else: self.redirect("/login") class LoginHandler(BaseHandler): def get(self): ‘‘‘ 当用户访登录的时候我们就得给他写cookie了,但是这里没有写在哪里写了呢? 在哪里呢?之前写的Handler都是继承的RequestHandler,这次继承的是BaseHandler是自己写的Handler 继承自己的类,在类了加扩展initialize! 在这里我们可以在这里做获取用户cookie或者写cookie都可以在这里做 ‘‘‘ ‘‘‘ 我们知道LoginHandler对象就是self,我们可不可以self.set_cookie()可不可以self.get_cookie() ‘‘‘ # self.set_cookie() # self.get_cookie() self.render(‘login.html‘, **{‘status‘: ‘‘}) def post(self, *args, **kwargs): #获取用户提交的用户名和密码 username = self.get_argument(‘username‘) password = self.get_argument(‘pwd‘) if username == ‘wupeiqi‘ and password == ‘123‘: #如果认证通过之后就可以访问这个self.my_session对象了!然后我就就可以吧Cookie写入到字典中了,NICE self.my_session[‘is_login‘] = ‘true‘ ‘‘‘ 这里用到知识点是类里的: class Foo(object): def __getitem__(self,key): print ‘__getitem__‘,key def __setitem__(self,key,value): print ‘__setitem__‘,key,value def __delitem__(self,key): print ‘__delitem__‘,key obj = Foo() result = obj[‘k1‘] #自动触发执行 __getitem__ obj[‘k2‘] = ‘wupeiqi‘ #自动触发执行 __setitem__ del obj[‘k1‘] #自动触发执行 __delitme__ ‘‘‘ self.redirect(‘/index‘) else: self.render(‘login.html‘, **{‘status‘: ‘用户名或密码错误‘}) settings = { ‘template_path‘: ‘template‘, ‘static_path‘: ‘static‘, ‘static_url_prefix‘: ‘/static/‘, ‘cookie_secret‘: ‘aiuasdhflashjdfoiuashdfiuh‘, ‘login_url‘: ‘/login‘ } application = tornado.web.Application([ #创建两个URL 分别对应 MainHandler LoginHandler (r"/index", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script src="/statics/jquery-1.12.4.js"> function UploadFile(){ var fileObj = $("#img")[0].files[0]; var form = new FormData(); form.append("user", "v1"); form.append("favor", "1"); form.append("fafafa", "fileObj"); $.ajax({ type:‘POST‘, url:‘/index‘, data:form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg) { console.log(arg); } }) } </script> </body> </html>
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
IMG_LIST = []
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render(‘index.html‘, img_list=IMG_LIST)
def post(self, *args, **kwargs):
print(self.get_argument(‘user‘))
print(self.get_arguments(‘favor‘))
file_metas = self.request.files["fafafa"]
# print(file_metas)
for meta in file_metas:
# 要上传的文件名
file_name = meta[‘filename‘]
import os
with open(os.path.join(‘statics‘, ‘img‘, file_name), ‘wb‘) as up:
up.write(meta[‘body‘])
IMG_LIST.append(file_name)
self.write(‘{"status": 1, "message": "mmmm"}‘)
settings = {
‘template_path‘: ‘views‘,
‘static_path‘: ‘statics‘,
‘static_url_prefix‘: ‘/statics/‘,
}
application = tornado.web.Application([
(r"/index", IndexHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
源码文件夹:http://pan.baidu.com/s/1slL6gFV
xhr上传
jquery上传
基于iframe上传
源码文件夹:http://pan.baidu.com/s/1slL6gFV
验证码原理在于后台自动创建一张带有随机内容的图片,然后将内容通过img标签输出到页面。
源码文件夹:http://pan.baidu.com/s/1slL6gFV
面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ 、__delitem__、__setitem__方法
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key): print ‘__getitem__‘,key def __setitem__(self, key, value): print ‘__setitem__‘,key,value def __delitem__(self, key): print ‘__delitem__‘,key obj = Foo() result = obj[‘k1‘] #obj[‘k2‘] = ‘wupeiqi‘ #del obj[‘k1‘]
Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作
class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.xxoo = "wupeiqi" class MainHandler(BaseHandler): def get(self): print(self.xxoo) self.write(‘index‘) class IndexHandler(BaseHandler): def get(self): print(self.xxoo) self.write(‘index‘)
session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from hashlib import sha1 import os, time session_container = {} create_session_id = lambda: sha1(‘%s%s‘ % (os.urandom(16), time.time())).hexdigest() class Session(object): session_id = "__sessionId__" def __init__(self, request): session_value = request.get_cookie(Session.session_id) if not session_value: self._id = create_session_id() else: self._id = session_value request.set_cookie(Session.session_id, self._id) def __getitem__(self, key): return session_container[self._id][key] def __setitem__(self, key, value): if session_container.has_key(self._id): session_container[self._id][key] = value else: session_container[self._id] = {key: value} def __delitem__(self, key): del session_container[self._id][key] class BaseHandler(tornado.web.RequestHandler): def initialize(self): # my_session[‘k1‘]访问 __getitem__ 方法 self.my_session = Session(self) class MainHandler(BaseHandler): def get(self): print self.my_session[‘c_user‘] print self.my_session[‘c_card‘] self.write(‘index‘) class LoginHandler(BaseHandler): def get(self): self.render(‘login.html‘, **{‘status‘: ‘‘}) def post(self, *args, **kwargs): username = self.get_argument(‘name‘) password = self.get_argument(‘pwd‘) if username == ‘wupeiqi‘ and password == ‘123‘: self.my_session[‘c_user‘] = ‘wupeiqi‘ self.my_session[‘c_card‘] = ‘12312312309823012‘ self.redirect(‘/index‘) else: self.render(‘login.html‘, **{‘status‘: ‘用户名或密码错误‘}) settings = { ‘template_path‘: ‘template‘, ‘static_path‘: ‘static‘, ‘static_url_prefix‘: ‘/static/‘, ‘cookie_secret‘: ‘aiuasdhflashjdfoiuashdfiuh‘, ‘login_url‘: ‘/login‘ } application = tornado.web.Application([ (r"/index", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() 自定义Session
在Web程序中往往包含大量的表单验证的工作,如:判断输入是否为空,是否符合规则。
上面实例的源码文件夹:http://pan.baidu.com/s/1slL6gFV
更多Tornado知识详见:http://demo.pythoner.com/itt2zh/ch1.html
http://www.cnblogs.com/wupeiqi/articles/5702910.html
http://www.cnblogs.com/luotianshuai/p/5386494.html
原文:http://www.cnblogs.com/kongqi816-boke/p/5699866.html