Tornado的使用

Tornado是非阻塞式web服务器,另外,Tornado还是一个支持WebSocket的优秀框架

`pip3 install tornado`

快速开始

#!/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()

 Tornado是一个非阻塞的web服务器以及web框架,但是在使用的时候只有使用异步的库才会真正发挥它异步的优势,因为异步的库返回的是Future对象

在3.0版本之后,gen.coroutine模块显得比较突出。coroutine装饰器可以让本来靠回调的异步编程看起来像同步编程。

其中便是利用了Python中生成器的Send函数。在生成器中,yield关键字往往会与正常函数中的return相比。它可以被当成迭代器,从而使用next()返回yield的结果。

但是生成器还有另外一个用法,就是使用send方法。在生成器内部可以将yield的结果赋值给一个变量,而这个值是通过外部的生成器client来send的

import tornado.ioloop
import tornado.web
from tornado.httpclient import AsyncHTTPClient
from tornado import gen


class MainHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        client = AsyncHTTPClient()
        resp = yield client.fetch("https://www.baidu.com")  # 必须用异步的模块
        if resp.code == 200:
            self.write(str(resp))
        else:
            self.write("Fail")
        

application = tornado.web.Application([
    (r"/index", MainHandler),
])

if __name__ == "__main__":
    application.listen(8009)
    tornado.ioloop.IOLoop.instance().start()

路由系统

路由系统其实就是 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("buy.wupeiqi.com/index")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9]+)", StoryHandler),
])
   
application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])
   
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()
二级路由代码

 

静态文件

settings = {
    'template_path': 'template',    # 定义模板根目录
    'static_path': 'jingtai',        # 定义静态文件根目录,使用:"/static/xx.jpg"
    'static_url_prefix': '/jt/',     # 使用:"/jt/xx.jpg"
}

模板引擎

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html", list_info = [11,22,33], k='a1')

渲染变量:{{   }}

条件语句:{% if len(items) > 2 %} ... {% else %} .... {% end %}

循环:{% for item in list_info %}    {{ item }}  {%  end %}

css、js渲染: 

<link href="{{static_url("css/common.css")}}" rel="stylesheet" />
<script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>

其他方法:

在模板中默认提供了一些函数、字段、类以供模板使用:

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 的別名

 模板复用:

header.html

<div>
    <ul>
        <li>USA</li>
        <li>51区</li>
    </ul>
</div>

使用:{%  include  'header.html'  %}

模板继承:

############## layout.html #################
<!DOCTYPE html>
<html>
<head>
    ....
    {% block CSS %}{% end %}
    ....
</head>
<body>

   ......
    
    {% block RenderBody %} {% end %}
   
    .......
    {% block JavaScript %}{% end %}
</body>
</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 %}

自定义UIMethod以UIModule

  类似于django的自定义标签(定义-注册-使用)

from tornado.web import UIModule
from tornado import escape


"""1. 定义"""
################ uimodules.py ###############
class custom(UIModule):
    def render(self, *args, **kwargs):
        return escape.xhtml_escape('<h1>wupeiqi</h1>')
############################################

################ uimethod.py ###############
def tab(self):
    return 'UIMethod'
############################################

"""2. 注册"""
import uimodules as md
import uimethods as mt

settings = {
    'ui_methods': mt,
    'ui_modules': md,
}


"""3. 使用"""
'''
{% module custom(123) %}
{{ tab() }}
'''

CSRF

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>
普通表单使用

使用:ajax

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使用

cookie

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!")
cookie基本操作

cookie加密

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!")
        else:
            self.write("Your cookie was set!")
             
application = tornado.web.Application([
    (r"/", MainHandler),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
签名cookie的使用

签名Cookie的本质是:

写cookie过程:

  • 将值进行base64加密
  • 对除值以外的内容进行签名,哈希算法(无法逆向解析)
  • 拼接 签名 + 加密值

读cookie过程:

  • 读取 签名 + 加密值
  • 对签名进行验证
  • base64解密,获取值内容

form表单+iframe实现局部刷新

11

原文地址:https://www.cnblogs.com/staff/p/13149946.html