tornado static path静态文件访问 必须是static头 为什么

如何开启Tornado的调试模式 -- 简明现代魔法Tornado基本使用 - 让我们忘了那片海 - 博客园
随笔 - 53, 文章 - 0, 评论 - 12, 引用 - 0
一、快速上手
#!/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()
第一步:执行脚本,监听 8888 端口
第二步:浏览器客户端访问 /index &--& &http://127.0.0.1:8888/index
第三步:服务器接受请求,并交由对应的类处理该请求
第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
第五步:方法返回值的字符串内容发送浏览器
二、路由系统
&路由系统其实就是 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 StoryHandler(tornado.web.RequestHandler):
def get(self, story_id):
self.write("You requested the story " + story_id)
class BuyHandler(tornado.web.RequestHandler):
def get(self):
self.write("/index")
application = tornado.web.Application([
(r"/index", MainHandler),
(r"/story/([0-9]+)", StoryHandler),
application.add_handlers('$', [
(r'/index',BuyHandler),
if __name__ == "__main__":
application.listen(80)
tornado.ioloop.IOLoop.instance().start()
Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
Tornado 的模板支持&控制语句&和&表达语句&,控制语句是使用&{%&和&%}&包起来的 例如&{% if len(items) & 2 %}。表达语句是使用&{{&和&}}&包起来的,例如&{{ items[0] }}。
控制语句和对应的 Python 语句的格式基本完全相同。我们支持&if、for、while&和&try,这些语句逻辑结束的位置需要用&{% end %}&做标记。还通过&extends&和&block&语句实现了模板继承。这些在&&的代码文档中有着详细的描述。
&!DOCTYPE html&
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"/&
&title&123456&/title&
&link href="{{static_url("css/common.css")}}" rel="stylesheet" /&
{% block CSS %}{% end %}
&div class="pg-header"&
{% block RenderBody %}{% end %}
&script src="{{static_url("js/jquery-1.8.2.min.js")}}"&&/script&
{% block JavaScript %}{% end %}
layout.html
{% extends 'layout.html'%}
{% block CSS %}
&link href="{{static_url("css/index.css")}}" rel="stylesheet" /&
&link href="/static/css/common.css" rel="stylesheet" /&
{% block RenderBody %}
&h1&Index&/h1&
{% block JavaScript %}
#!/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()
在模板中默认提供了一些函数、字段、类以供模板使用:
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的功能:
# uimethods.py
def tab(self):
return 'UIMethod'
uimethods.py
#!/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&chenchao&/h1&')
uimodules.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#!/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()
&!DOCTYPE html&
&head lang="en"&
&meta charset="UTF-8"&
&title&&/title&
&link href="{{static_url("commons.css")}}" rel="stylesheet" /&
&h1&hello&/h1&
{% module custom(123) %}
{{ tab() }}
index.html
&四、实用功能
1、静态文件
对于静态文件,可以配置静态文件的目录和前段使用时的前缀,并且Tornaodo还支持静态文件缓存。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
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(8888)
tornado.ioloop.IOLoop.instance().start()
&!DOCTYPE html&
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"/&
&title&123456&/title&
&link href="{{static_url("css/common.css")}}" rel="stylesheet" /&
&div class="pg-header"&
&h1&Index&/h1&
&script src="{{static_url("js/jquery-1.8.2.min.js")}}"&&/script&
index.html
备注:静态文件缓存的实现
def get_content_version(cls, abspath):
data = cls.get_content(abspath)
hasher = hashlib.md5()
if isinstance(data, bytes):
hasher.update(data)
for chunk in data:
hasher.update(chunk)
return hasher.hexdigest()
静态文件缓存源码
Tornado中的跨站请求伪造和Django中的相似,
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"/&
普通表单使用
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] :
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使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求
&3、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!")
self.write("Your cookie was set!")
Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:
class MainHandler(tornado.web.RequestHandler):
def get(self):
if not self.get_secure_cookie("mycookie"):
self.set_secure_cookie("mycookie", "myvalue")
self.write("Your cookie was not set yet!")
self.write("Your cookie was set!")
application = tornado.web.Application([
(r"/", MainHandler),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
签名Cookie的本质是:
写cookie过程:
将值进行base64加密
对除值以外的内容进行签名,哈希算法(无法逆向解析)
拼接 签名 + 加密值
读cookie过程:
读取 签名 + 加密值
对签名进行验证
base64解密,获取值内容
&注:许多API验证机制和安全cookie的实现机制相同。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
login_user = self.get_secure_cookie("login_user", None)
if login_user:
self.write(login_user)
self.redirect('/login')
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.current_user()
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.set_secure_cookie('login_user', '陈超')
self.redirect('/')
self.render('login.html', **{'status': '用户名或密码错误'})
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh'
application = tornado.web.Application([
(r"/index", MainHandler),
(r"/login", LoginHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
基于cookie进行用户验证
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
return self.get_secure_cookie("login_user")
class MainHandler(BaseHandler):
@tornado.web.authenticated
def get(self):
login_user = self.current_user
self.write(login_user)
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.current_user()
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.set_secure_cookie('login_user', '陈超')
self.redirect('/')
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()
Tornado内部提供cookie验证
五、扩展功能
&1、自定义Session
a.知识储备
类的特殊成员
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):
def __getitem__(self, key):
'__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'] = 'chenchao'
#del obj['k1']
b.session实现机制
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
session_container = {}
# 创建MD516进制的session_id
create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
class Session(object):
session_id = "__sessionId__"
# 自定义session的key名称
def __init__(self, request):    
# 默认先从请求信息里获取自定义的cookie值
session_value = request.get_cookie(Session.session_id)
if not session_value:
self._id = create_session_id()
self._id = session_value
# 设置cookie
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
session_container[self._id] = {key: value}
def __delitem__(self, key):
del session_container[self._id][key]
class BaseHandler(tornado.web.RequestHandler):
def initialize(self):
# 创建Session的对象,将MainHandler的对象传入
self.my_session = Session(self)
# 继承自定义的BaseHandler
class MainHandler(BaseHandler):
def get(self):
print self.my_session['c_user']
# 获取session的值
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 == 'chenchao' and password == '123':
# 设置session的值
self.my_session['c_user'] = 'chenchao'
self.my_session['c_card'] = '23012'
self.redirect('/index')
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()
&2、自定义模型绑定
模型绑定有两个主要功能:
自动生成html表单
用户输入验证
在之前学习的Django中为程序员提供了非常便捷的模型绑定功能,但是在Tornado中,一切需要自己动手!!!
&!DOCTYPE html&
&head lang="en"&
&meta charset="UTF-8"&
&title&&/title&
&link href="{{static_url("commons.css")}}" rel="stylesheet" /&
&h1&hello&/h1&
&form action="/index" method="post"&
&p&hostname: &input type="text" name="host" /& &/p&
&p&ip: &input type="text" name="ip" /& &/p&
&p&port: &input type="text" name="port" /& &/p&
&p&phone: &input type="text" name="phone" /& &/p&
&input type="submit" /&
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
class MainForm(object):
def __init__(self):
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$'
def check_valid(self, request):
form_dict = self.__dict__
for key, regular in form_dict.items():
post_value = request.get_argument(key)
# 让提交的数据 和 定义的正则表达式进行匹配
ret = re.match(regular, post_value)
print key,ret,post_value
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def post(self, *args, **kwargs):
obj = MainForm()
result = obj.check_valid(self)
self.write('ok')
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
'login_url': '/login'
application = tornado.web.Application([
(r"/index", MainHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
&由于请求的验证时,需要考虑是否可以为空以及正则表达式的复用,所以:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
class Field(object):
def __init__(self, error_msg_dict, required):
self.id_valid = False
self.value = None
self.error = None
self.name = None
self.error_msg = error_msg_dict
self.required = required
def match(self, name, value):
self.name = name
if not self.required:
self.id_valid = True
self.value = value
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
self.error = "%s is required" % name
ret = re.match(self.REGULAR, value)
self.id_valid = True
self.value = ret.group()
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
self.error = "%s is invalid" % name
class IPField(Field):
REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {}
# {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(IPField, self).__init__(error_msg_dict=error_msg, required=required)
class IntegerField(Field):
REGULAR = "^\d+$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {'required': '数字不能为空', 'valid': '数字格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(IntegerField, self).__init__(error_msg_dict=error_msg, required=required)
class CheckBoxField(Field):
def __init__(self, error_msg_dict=None, required=True):
error_msg = {}
# {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(CheckBoxField, self).__init__(error_msg_dict=error_msg, required=required)
def match(self, name, value):
self.name = name
if not self.required:
self.id_valid = True
self.value = value
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
self.error = "%s is required" % name
if isinstance(name, list):
self.id_valid = True
self.value = value
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
self.error = "%s is invalid" % name
class FileField(Field):
REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {}
# {'required': '数字不能为空', 'valid': '数字格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(FileField, self).__init__(error_msg_dict=error_msg, required=required)
def match(self, name, value):
self.name = name
self.value = []
if not self.required:
self.id_valid = True
self.value = value
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
self.error = "%s is required" % name
m = re.compile(self.REGULAR)
if isinstance(value, list):
for file_name in value:
r = m.match(file_name)
self.value.append(r.group())
self.id_valid = True
self.id_valid = False
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
self.error = "%s is invalid" % name
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
self.error = "%s is invalid" % name
def save(self, request, upload_path=""):
file_metas = request.files[self.name]
for meta in file_metas:
file_name = meta['filename']
with open(file_name,'wb') as up:
up.write(meta['body'])
class Form(object):
def __init__(self):
self.value_dict = {}
self.error_dict = {}
self.valid_status = True
def validate(self, request, depth=10, pre_key=""):
self.initialize()
self.__valid(self, request, depth, pre_key)
def initialize(self):
def __valid(self, form_obj, request, depth, pre_key):
验证用户表单请求的数据
:param form_obj: Form对象(Form派生类的对象)
:param request: Http请求上下文(用于从请求中获取用户提交的值)
:param depth: 对Form内容的深度的支持
:param pre_key: Html中name属性值的前缀(多层Form时,内部递归时设置,无需理会)
:return: 是否验证通过,True:验证成功;False:验证失败
depth -= 1
if depth & 0:
return None
form_field_dict = form_obj.__dict__
for key, field_obj in form_field_dict.items():
print key,field_obj
if isinstance(field_obj, Form) or isinstance(field_obj, Field):
if isinstance(field_obj, Form):
# 获取以key开头的所有的值,以参数的形式传至
self.__valid(field_obj, request, depth, key)
if pre_key:
key = "%s.%s" % (pre_key, key)
if isinstance(field_obj, CheckBoxField):
post_value = request.get_arguments(key, None)
elif isinstance(field_obj, FileField):
post_value = []
file_list = request.request.files.get(key, None)
for file_item in file_list:
post_value.append(file_item['filename'])
post_value = request.get_argument(key, None)
print post_value
# 让提交的数据 和 定义的正则表达式进行匹配
field_obj.match(key, post_value)
if field_obj.id_valid:
self.value_dict[key] = field_obj.value
self.error_dict[key] = field_obj.error
self.valid_status = False
class ListForm(object):
def __init__(self, form_type):
self.form_type = form_type
self.valid_status = True
self.value_dict = {}
self.error_dict = {}
def validate(self, request):
name_list = request.request.arguments.keys() + request.request.files.keys()
flag = False
while True:
pre_key = "[%d]" % index
for name in name_list:
if name.startswith(pre_key):
flag = True
form_obj = self.form_type()
form_obj.validate(request, depth=10, pre_key="[%d]" % index)
if form_obj.valid_status:
self.value_dict[index] = form_obj.value_dict
self.error_dict[index] = form_obj.error_dict
self.valid_status = False
index += 1
flag = False
class MainForm(Form):
def __init__(self):
# self.ip = IPField(required=True)
# self.port = IntegerField(required=True)
# self.new_ip = IPField(required=True)
# self.second = SecondForm()
self.fff = FileField(required=True)
super(MainForm, self).__init__()
# class SecondForm(Form):
def __init__(self):
self.ip = IPField(required=True)
self.new_ip = IPField(required=True)
super(SecondForm, self).__init__()
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def post(self, *args, **kwargs):
# for i in
dir(self.request):
# print self.request.arguments
# print self.request.files
# print self.request.query
# name_list = self.request.arguments.keys() + self.request.files.keys()
# print name_list
# list_form = ListForm(MainForm)
# list_form.validate(self)
# print list_form.valid_status
# print list_form.value_dict
# print list_form.error_dict
# obj = MainForm()
# obj.validate(self)
# print "验证结果:", obj.valid_status
# print "符合验证结果:", obj.value_dict
# print "错误信息:"
# for key, item in obj.error_dict.items():
print key,item
# print self.get_arguments('favor'),type(self.get_arguments('favor'))
# print self.get_argument('favor'),type(self.get_argument('favor'))
# print type(self.get_argument('fff')),self.get_argument('fff')
# print self.request.files
# obj = MainForm()
# obj.validate(self)
# print obj.valid_status
# print obj.value_dict
# print obj.error_dict
# print self.request,type(self.request)
# obj.fff.save(self.request)
# from tornado.httputil import HTTPServerRequest
# name_list = self.request.arguments.keys() + self.request.files.keys()
# print name_list
# print self.request.files,type(self.request.files)
# print len(self.request.files.get('fff'))
# obj = MainForm()
# obj.validate(self)
# print obj.valid_status
# print obj.value_dict
# print obj.error_dict
# obj.fff.save(self.request)
self.write('ok')
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
'login_url': '/login'
application = tornado.web.Application([
(r"/index", MainHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Form验证框架
Form验证框架

我要回帖

更多关于 static静态代码块 的文章

 

随机推荐