Tornado Web Framework
1 基本使用
import json
import os
import tornado.ioloop
import tornado.web
BASE_DIR = os.path.dirname(__file__)
settings = {
"template_path": os.path.join(BASE_DIR, "templates"), # 存放模板的文件夹 html
"static_path": os.path.join(BASE_DIR, "static"), # 存放静态文件的文件夹 css js
"debug": True,
"autoreload": True,
"cookie_secret": "TozDU7esgEUTqQy0M6c5II8==", # 安全cookie
"xsrf_cookies": False,
}
class IndexHandler(tornado.web.RequestHandler):
def get(self):
result = {"hello": "world"}
# self.render("index.html")
self.write(json.dumps(result))
if __name__ == '__main__':
application = tornado.web.Application(
[
(r"/index", IndexHandler),
],
**settings)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
2 常规配置
debug或者autoreload为True时,修改源文件代码将会自动重启服务,相当于Django的重启功能
| 设置项 | 描述 |
|---|---|
| autoreload | 如果True,任何源文件更改时服务器进程将重新启动,如调试模式和自动重新加载中所述。此选项是Tornado 3.2中的新选项; 以前此功能由debug设置控制 |
| debug | 几种调试模式设置的简写,在调试模式和自动重新加载中描述。设置debug=True相当于autoreload=True,compiled_template_cache=False,static_hash_cache=False,serve_traceback=True |
| default_handler_class|default_handler_args | 如果没有找到其他匹配项,将使用此处理程序; 使用它来实现自定义404页面(Tornado 3.2中的新增功能) |
| compress_response | 如果True,文本格式的响应将自动压缩。Tornado 4.0的新功能 |
| gzip | compress_response自Tornado 4.0以来已弃用的别名 |
| log_function | 此函数将在每个记录结果的请求结束时调用(使用一个参数,即RequestHandler对象)。默认实现将写入logging模块的根记录器。也可以通过覆盖来定制Application.log_request。可以自定制日志的输出格式 |
| serve_traceback | 如果True,默认错误页面将包含错误的回溯。此选项是Tornado 3.2中的新选项; 以前此功能由debug设置控制 |
| ui_modules | ui_methods | 可以设置为UIModule可用于模板的映射或UI方法。可以设置为模块,字典或模块和/或dicts列表。有关详细信息,请参阅UI模块。 |
| websocket_ping_interval | 如果设置为数字,则每n秒钟将对所有websockets进行ping操作。这有助于通过关闭空闲连接的某些代理服务器保持连接活动,并且它可以检测websocket是否在未正确关闭的情况下发生故障。 |
| websocket_ping_timeout | 如果设置了ping间隔,并且服务器在这么多秒内没有收到“pong”,它将关闭websocket。默认值是ping间隔的三倍,最少30秒。如果未设置ping间隔,则忽略。 |
3 身份/验证/安全
| 设置项 | 描述 |
|---|---|
| cookie_secret | 用于RequestHandler.get_secure_cookie 和set_secure_cookie签署cookie |
| key_version | set_secure_cooki 当cookie_secret是密钥字典时,requestHandler 使用特定密钥对cookie进行签名 |
| login_url | authenticated如果用户未登录,装饰器将重定向到此URL。可以通过覆盖进一步自定义RequestHandler.get_login_url |
| xsrf_cookies | 如果True,将启用跨站点请求伪造保护 |
| xsrf_cookie_version | 控制此服务器生成的新XSRF cookie的版本。通常应该保留默认值(它始终是支持的最高版本),但可以在版本转换期间临时设置为较低的值。Tornado 3.2.2中的新功能,它引入了XSRF cookie版本2 |
| xsrf_cookie_kwargs | 可以设置为要传递给RequestHandler.set_cookie XSRF cookie 的其他参数的字典 |
| twitter_consumer_key | 所用的 tornado.auth模块来验证各种API,如检测这些种类账号是否登录等... |
| twitter_consumer_secret | 同上.. |
| friendfeed_consumer_key | 同上.. |
| friendfeed_consumer_secret | 同上.. |
| google_consumer_key | 同上.. |
| google_consumer_secret | 同上.. |
| facebook_api_key | 同上.. |
| facebook_secret | 同上.. |
4 模板设置
| 设置项 | 描述 |
|---|---|
| autoescape | 控制模板的自动转义。可以设置为None禁用转义,或者设置 应该传递所有输出的函数的名称。默认为"xhtml_escape"。可以使用该指令在每个模板的基础上进行更改。% autoescape % |
| compiled_template_cache | 默认是True; 如果False每个请求都会重新编译模板。此选项是Tornado 3.2中的新选项; 以前此功能由debug设置控制 |
| template_path | 包含模板文件的目录。可以通过覆盖进一步定制RequestHandler.get_template_path |
| template_loader | 分配给tornado.template.BaseLoader自定义模板加载的实例 。如果使用此 设置,则忽略template_path和autoescape设置。可以通过覆盖进一步定制RequestHandler.create_template_loader |
| template_whitespace | 控制模板中空格的处理; 查看tornado.template.filter_whitespace允许的值。Tornado 4.3中的新功能 |
5 静态文件
| 设置项 | 描述 |
|---|---|
| static_hash_cache | 默认是True; 如果False 每次请求都会重新计算静态网址。此选项是Tornado 3.2中的新选项; 以前此功能由debug设置控制 |
| static_path | 将从中提供静态文件的目录 |
| static_url_prefix | 静态文件的Url前缀,默认为/static/ |
| static_handler_class | static_handler_args | 可以设置为静态文件而不是默认文件使用不同的处理程序 tornado.web.StaticFileHandler。 static_handler_args如果设置,则应该是要传递给处理程序initialize方法的关键字参数的字典。 |
6 路由和参数匹配
在tornado中,一个url对应一个处理类。
6.1 无名分组
使用正则分组()解析出资源请求地址的一些参数。匹配到的参数会通过位置传参的形式传递给控制器处理函数,所以接收参数可以任意命名,因此你可以通过 *args 接收到所有匹配的参数
import tornado.ioloop
import tornado.web
settings = {"debug": True}
# http://127.0.0.1:8888/register1/soloman
# http://127.0.0.1:8888/register2/soloman
class RegisterHandler1(tornado.web.RequestHandler):
def get(self, *args):
self.write(str(args)) # ('soloman',)
class RegisterHandler2(tornado.web.RequestHandler):
def get(self, params):
self.write(params) # soloman
application = tornado.web.Application([
(r"^/register1/(\w+)", RegisterHandler1),
(r"^/register2/(\w+)", RegisterHandler2),
], **settings)
if __name__ == '__main__':
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
6.2 有名分组
使用正则的有名分组(?P<组名>规则)解析出资源请求地址的一些参数。匹配到的参数会通过关键字传参的形式传递给控制器处理函数,所以接收参数必须与组名相同,因此你可以通过**kwargs接收到所有匹配的参数
import tornado.ioloop
import tornado.web
settings = {"debug": True}
# http://127.0.0.1:8888/register1/soloman
# http://127.0.0.1:8888/register2/soloman
class RegisterHandler1(tornado.web.RequestHandler):
def get(self, **kwargs):
self.write(str(kwargs)) # {'username': 'soloman'}
class RegisterHandler2(tornado.web.RequestHandler):
def get(self, username):
self.write(username) # soloman
application = tornado.web.Application([
(r"^/register1/(?P<username>\w+)", RegisterHandler1),
(r"^/register2/(?P<username>\w+)", RegisterHandler2),
], **settings)
if __name__ == '__main__':
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
注意:路由匹配的参数捕捉,不允许无名分组和有名分组的混合使用,这会引发一个异常
6.3 反向解析
反向解析要与路由命名配合使用
import tornado.ioloop
import tornado.web
settings = {"debug": True}
# http://127.0.0.1:8888/register
class RegisterHandler(tornado.web.RequestHandler):
def get(self):
print(self.reverse_url("reg")) # /register
self.write("注册页面")
# 使用tornado.web.url来进行添加路由规则
application = tornado.web.Application([
tornado.web.url(r'/register', RegisterHandler, name="reg")
], **settings)
if __name__ == '__main__':
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
7 请求处理类
在tornado中,请求处理类都继承了一个叫做tornado.web.RequestHandler的类。以下是常用的获取相关属性以及方法
| 属性/方法 | 描述 |
|---|---|
| self.request | 获取用户请求相关信息 |
| self._headers | 获取请求头信息,基本请求头被过滤 |
| self.request.headers | 获取请求头信息,包含基本请求头 |
| slef.request.body | 获取请求体信息,bytes格式 |
| self.request.remote_ip | 获取客户端IP |
| self.request.method | 获取请求方式 |
| self.request.version | 获取所使用的HTTP版本 |
| self.get_query_argument() | 获取单个GET中传递过来的参数,如果多个参数同名,获取最后一个 |
| slef.get_query_arguments() | 获取所有GET中传递过来的参数,返回列表的形式 |
| self.get_body_argument() | 获取单个POST中传递过来的参数,如果多个参数同名,获取最后一个 |
| self.get_body_arguments() | 获取所有POST中传递过来的参数,返回列表的形式 |
| self.get_argument() | 获取单个GET/POST中传递过来的参数,如果多个参数同名,获取最后一个 |
| self.get_arguments() | 获取所有GET/POST中传递过来的参数,返回列表的形式 |
| self.request.files | 获取所有通过 multipart/form-data POST 请求上传的文件 |
| self.request.host | 获取主机名 |
| self.request.uri | 获取请求的完整资源标识,包括路径和查询字符串 |
| self.request.query | 获取查询字符串的部分 |
| self.request.path | 获取请求的路径( ?之前的所有内容) |
8 HTTP 响应
响应一般就分为以下几种,返回单纯的字符串,返回一个模板页面,返回JSON格式数据,返回一个错误,以及重定向
self.write("OK")
self.render("templatePath", **kwargs) # 传递给模板的数据
import json
json_data = json.dumps({"k1": "v1"})
self.write(json_data)
self.send_error(404)
self.finish() # 结束本次请求
self.redirect("www.soloman.vip", status=301)
# 设置响应头
self.set_header("k1", 1)
self.add_header("k2", 2)
self.clear_header("k1")
在响应处理类中定义钩子函数
class APIHandler(tornado.web.RequestHandler):
def set_default_headers(self):
print("first--设置headers")
def initialize(self):
print("second--初始化")
def prepare(self):
print("third--准备工作")
def get(self):
print("fourth--处理get请求")
def post(self):
print('fourth--处理post请求')
def write_error(self, status_code, **kwargs):
print("fifth--处理错误")
def on_finish(self):
print("sixth--处理结束,释放资源--")
9 模板语法
Tornado 大部分模板语法和 Django 类似。模板传参可以通过k=v的方式传递,也可以通过**dict的方式进行解包传递
class APIHandler(tornado.web.RequestHandler):
def get(self):
context = {
"name": "Soloman",
"age": 18,
"hobby": ["篮球", "唱歌", "跳舞"]
}
self.render("api.html", **context)
# self.render("api.html", name="Soloman", age=18, hobby=["篮球", "唱歌", "跳舞"])
模板中有两种表现形式,一种是以双层{}进行包裹,另一种是命令形式以% 命令 %包裹。注意:tornado的模板语法的结束标识是% end %,不是Django或jinja2的% endblock %
tornado中的模板语言允许导入Python包、模块
% import time %
{ time.time() }
% from util.modify import mul %
{mul(6,6)}
9.1 ui_modules
ui_modules定义一些公用的组件,在这里返回的字符串将默认关闭HTML字符转义功能。
| 需要覆写的方法 | 描述 |
|---|---|
| render() | 覆写该方法,返回该UI模块的输出 |
| embedded_javascript() | 覆写该方法,返回一段JavaScript代码字符串,它将会在模板中自动添加script标签,并且该script标签内部会填入该方法返回的JavaScript代码字符串 |
| javascript_files() | 覆写该方法,返回值应当是str,它将会在模板中自动添加script标签并且该script标签的src属性会指向该方法所返回的字符串,如果返回值是一个相对路径,则会去application的settings中寻找静态资源的path做拼接 |
| embedded_css() | 覆写该方法,返回一段CSS代码字符串,它将会在模板中自动添加style标签,并且该style标签内部会填入该方法返回的CSS代码字符串 |
| css_files() | 覆写该方法,返回值应当是str,它将会在模板中自动添加link标签并且该link标签的href属性会指向该方法所返回的字符串,如果返回值是一个相对路径,则会去application的settings中寻找静态资源的path做拼接 |
| html_head() | 重写该方法,返回值将放置在head元素中的HTML字符串。 |
| html_body() | 重写该方法,返回值将放置在body元素末尾的HTML字符串。 |
| render_string() | 渲染模板并将其作为字符串返回。 |
10 cookies
10.1 基本操作
| 方法 | 描述 |
|---|---|
| self.get_cookie() | 获取cookie键值对 |
| self.set_cookie() | 设置cookie键值对,参数expires可设置过期时间(日期:datetime/time,默认30天),expires_day设置过期天数(优先级更高),示例:expirse = time.time() + 60 * 60 * 24 * 7 |
class APIHandler(tornado.web.RequestHandler):
def get(self):
if self.get_cookie("access"):
self.write("你来访问过了")
else:
self.set_cookie("access","yes")
self.write("七天内可再次访问")
10.2 加密 cookies
在application的配置项中设定一个加密的盐cookie_secret,然后使用下面的两个方法进行加密cookies的操作
| 方法 | 描述 |
|---|---|
| self.get_secure_cookie() | 获取cookie键值对,并对其进行解密 |
| self.set_secure_cookie() | 设置cookie键值对,将其与cookie_secret进行结合加密 |
class APIHandler(tornado.web.RequestHandler):
def get(self):
if self.get_secure_cookie("access"):
self.write("你来访问过了")
else:
self.set_secure_cookie("access", "yes")
self.write("七天内可再次访问")
settings = {
"debug": True,
"template_path": "templates", # 指定模板目录
"static_path": "static", # 指定静态文件目录
"cookie_secret": "0dsa0D9d0a%39433**das9))|ddsa", # cookie加密的盐
}
application = tornado.web.Application([
tornado.web.url(r'/api', APIHandler),
], **settings)
