Python学习笔记_进阶篇(一)_浅析tornado web框架

这篇具有很好参考价值的文章主要介绍了Python学习笔记_进阶篇(一)_浅析tornado web框架。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

tornado简介

1、tornado概述

Tornado就是我们在 FriendFeed 的 Web 服务器及其常用工具的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题,请参阅The C10K problem)

Tornado代表嵌入实时应用中最新一代的开发和执行环境。 Tornado 包含三个完整的部分:

(1)、Tornado系列工具, 一套位于主机或目标机上强大的交互式开发工具和使用程序;

(2)、VxWorks 系统, 目标板上高性能可扩展的实时操作系统;

(3)、可选用的连接主机和目标机的通讯软件包 如以太网、串行线、在线仿真器或ROM仿真器。

2、tornado特点

Tornado的独特之处在于其所有开发工具能够使用在应用开发的任意阶段以及任何档次的硬件资源上。而且,完整集的Tornado工具可以使开发人员完全不用考虑与目标连接的策略或目标存储区大小。Tornado 结构的专门设计为开发人员和第三方工具厂商提供了一个开放环境。已有部分应用程序接口可以利用并附带参考书目,内容从开发环境接口到连接实现。Tornado包括强大的开发和调试工具,尤其适用于面对大量问题的嵌入式开发人员。这些工具包括C和C++源码级别的调试器,目标和工具管理,系统目标跟踪,内存使用分析和自动配置. 另外,所有工具能很方便地同时运行,很容易增加和交互式开发。

3、tornado模块索引

最重要的一个模块是web, 它就是包含了 Tornado 的大部分主要功能的 Web 框架。其它的模块都是工具性质的, 以便让 web 模块更加有用 后面的 Tornado 攻略 详细讲解了 web 模块的使用方法。

主要模块

  • web - FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能
  • escape - XHTML, JSON, URL 的编码/解码方法
  • database - 对 MySQLdb 的简单封装,使其更容易使用
  • template - 基于 Python 的 web 模板系统
  • httpclient - 非阻塞式 HTTP 客户端,它被设计用来和 webhttpserver 协同工作
  • auth - 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)
  • locale - 针对本地化和翻译的支持
  • options - 命令行和配置文件解析工具,针对服务器环境做了优化

底层模块

  • httpserver - 服务于 web 模块的一个非常简单的 HTTP 服务器的实现
  • iostream - 对非阻塞式的 socket 的简单封装,以方便常用读写操作
  • ioloop - 核心的 I/O 循环

tornado框架使用

1、安装tornado

pip install tornado
源码安装:https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

2、先写一个入门级的代码吧,相信大家都能看懂,声明:tornado内部已经帮我们实现socket。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.web
import tornado.ioloop

class IndexHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.write("Hello World, My name is 张岩林")

application = tornado.web.Application([
    (r'/index',IndexHandler),
])

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

第一步:执行脚本,监听 8080 端口

第二步:浏览器客户端访问 /index --> http://127.0.0.1:8080/index

第三步:服务器接受请求,并交由对应的类处理该请求

第四步:类接受到请求之后,根据请求方式(post / get / delete …)的不同调用并执行相应的方法

第五步:然后将类的方法返回给浏览器

tornado路由系统

在tornado web框架中,路由表中的任意一项是一个元组,每个元组包含pattern(模式)和handler(处理器)。当httpserver接收到一个http请求,server从接收到的请求中解析出url path(http协议start line中),然后顺序遍历路由表,如果发现url path可以匹配某个pattern,则将此http request交给web应用中对应的handler去处理。

由于有了url路由机制,web应用开发者不必和复杂的http server层代码打交道,只需要写好web应用层的逻辑(handler)即可。Tornado中每个url对应的是一个类。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
__auth__ = "zhangyanlin"

import tornado.web
import tornado.ioloop

class IndexHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.write("Hello World, My name is 张岩林")

class LoginHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.write("<input type = 'text'>")

class RegisterHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.write("<input type = 'password'>")

application = tornado.web.Application([
    (r'/index/(?P<page>\d*)',IndexHandler),  # 基础正则路由
    (r'/login',LoginHandler),
    (r'/register',RegisterHandler),
])

# 二级路由映射
application.add_handlers('buy.zhangyanlin.com$',[
    (r'/login', LoginHandler),
])

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

观察所有的网页的内容,下面都有分页,当点击下一页后面的数字也就跟着变了,这种就可以用基础正则路由来做,下面我来给大家下一个网页分页的案例吧

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-
__auth__ = "zhangyanlin"

import tornado.web
import tornado.ioloop

LIST_INFO = [
    {'username':'zhangyanlin','email':'133@164.com'}
]
for i in range(200):
    temp = {'username':str(i)+"zhang",'email':str(i)+"@163.com"}
    LIST_INFO.append(temp)


class Pagenation:

    def __init__(self,current_page,all_item,base_url):  #当前页 内容总数 目录
        try:
            page = int(current_page)
        except:
            page = 1
        if page < 1:
            page = 1

        all_page,c = divmod(all_item,5)
        if c > 0:
            all_page +=1

        self.current_page = page
        self.all_page = all_page
        self.base_url = base_url

    @property
    def start(self):
        return (self.current_page - 1) * 5

    @property
    def end(self):
        return self.current_page * 5

    def string_pager(self):
        list_page = []
        if self.all_page < 11:
            s = 1
            t = self.all_page + 1
        else:
            if self.current_page < 6:
                s = 1
                t = 12
            else:
                if (self.current_page + 5) < self.all_page:
                    s = self.current_page-5
                    t = self.current_page + 6
                else:
                    s = self.all_page - 11
                    t = self.all_page +1

        first = '<a href = "/index/1">首页</a>'
        list_page.append(first)
        # 当前页
        if self.current_page == 1:
            prev = '<a href = "javascript:void(0):">上一页</a>'
        else:
            prev = '<a href = "/index/%s">上一页</a>'%(self.current_page-1,)
        list_page.append(prev)

        #页码
        for p in range(s,t):
            if p== self.current_page:
                temp = '<a class = "active" href = "/index/%s">%s</a>'%(p,p)
            else:
                temp = '<a href = "/index/%s">%s</a>' % (p, p)
            list_page.append(temp)



        # 尾页
        if self.current_page == self.all_page:
            nex = '<a href = "javascript:void(0):">下一页</a>'
        else:
            nex = '<a href = "/index/%s">下一页</a>' % (self.current_page + 1,)
        list_page.append(nex)

        last = '<a href = "/index/%s">尾页</a>'%(self.all_page)
        list_page.append(last)


        #跳转
        jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/')
        script = '''
            <script>
                function Jump(baseUrl,ths){
                    var val = ths.previousElementSibling.value;
                    if (val.trim().length > 0){
                        location.href = baseUrl + val;
                    }
                }
            </script>
        '''
        list_page.append(jump)
        list_page.append(script)
        str_page = "".join(list_page)

        return str_page

class IndexHandler(tornado.web.RequestHandler):

    def get(self, page):
        obj = Pagenation(page,len(LIST_INFO),'/index/')
        current_list = LIST_INFO[obj.start:obj.end]
        str_page = obj.string_pager()
        self.render('index.html', list_info=current_list, current_page=obj.current_page, str_page=str_page)

application = tornado.web.Application([
    (r'/index/(?P<page>\d*)',IndexHandler)

])


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

tornado服务端demo

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .pager a{
            display: inline-block;
            padding: 5px 6px;
            margin: 10px 3px;
            border: 1px solid #2b669a;
            text-decoration:none;

        }
        .pager a.active{
            background-color: #2b669a;
            color: white;
        }
    </style>
</head>
<body>
    <h3>显示数据</h3>
    <table border="1">
        <thead>
            <tr>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            {% for line in list_info %}
                <tr>
                    <td>{{line['username']}}</td>
                    <td>{{line['email']}}</td>
                </tr>
            {% end %}
        </tbody>
    </table>
    <div class="pager">
        {% raw str_page %}
    </div>
</body>
</html>

前端HTML文件

注:两个文件必须放在同一个文件夹下,中间前端代码中有用到XSS攻击和模板语言,这两个知识点下面会详细解释

tornado 模板引擎

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {%%} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{}} 包起来的,例如 {{ items[0] }}

控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhiletry,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extendsblock 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

注:在使用模板前需要在setting中设置模板路径:“template_path” : “views”

settings = {
    'template_path':'views',             #设置模板路径,设置完可以把HTML文件放置views文件夹中
    'static_path':'static',              # 设置静态模板路径,设置完可以把css,JS,Jquery等静态文件放置static文件夹中
    'static_url_prefix': '/sss/',        #导入时候需要加上/sss/,例如<script src="/sss/jquery-1.9.1.min.js"></script>
    'cookie_secret': "asdasd",           #cookie生成秘钥时候需提前生成随机字符串,需要在这里进行渲染
    'xsrf_cokkies':True,                 #允许CSRF使用
}


application = tornado.web.Application([  
    (r'/index',IndexHandler),  
],**settings)                           #需要在这里加载

文件目录结构如下:

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

1、模板语言基本使用for循环,if…else使用,自定义UIMethod以UIModule

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import uimodule as md
import uimethod as mt

INPUT_LIST = []
class MainHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        name = self.get_argument('xxx',None)
        if name:
            INPUT_LIST.append(name)
        self.render("index.html",npm = "NPM88888",xxoo = INPUT_LIST)

    def post(self, *args, **kwargs):
        name = self.get_argument('xxx')
        INPUT_LIST.append(name)
        self.render("index.html", npm = "NPM88888", xxoo = INPUT_LIST)
        # self.write("Hello, World!!!")

settings = {
    'template_path':'tpl',  # 模板路径的配置
    'static_path':'statics',  # 静态文件路径的配置
    'ui_methods':mt,        # 自定义模板语言
    'ui_modules':md,        # 自定义模板语言
}

#路由映射,路由系统
application = tornado.web.Application([
    (r"/index",MainHandler),
],**settings)


if __name__ == "__main__":
    # 运行socket
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

start.py

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

from tornado.web import UIModule
from tornado import escape

class custom(UIModule):

    def render(self, *args, **kwargs):
        return "张岩林"

uimodule

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

def func(self,arg):
    return arg.lower()

uimethod

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link type="text/css" rel="stylesheet" href="static/commons.css">
</head>
<body>
    <script src="static/zhang.js"></script>
    <h1>Hello world</h1>
    <h1>My name is zhangyanlin</h1>
    <h1>输入内容</h1>
    <form action="/index" method="post">
        <input type="text" name="xxx">
        <input type="submit" value="提交">
    </form>
    <h1>展示内容</h1>
    <h3>{{ npm }}</h3>
    <h3>{{ func(npm)}}</h3>
    <h3>{% module custom() %}</h3>
    <ul>
        {% for item in xxoo %}
            {% if item == "zhangyanlin" %}
                <li style="color: red">{{item}}</li>
            {% else %}
                <li>{{item}}</li>
            {% end %}
        {% end %}
    </ul>
</body>
</html>

index.html

2、母板继承

(1)、相当于python的字符串格式化一样,先定义一个占位符

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!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

(2)、再子板中相应的位置继承模板的格式

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

{% 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

3、导入内容

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<div>
    <ul>
        <li>张岩林帅</li>
        <li>张岩林很帅</li>
        <li>张岩林很很帅</li>
    </ul>
</div>

content.html

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!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" />
</head>
<body>

    <div class="pg-header">
        {% include 'header.html' %}
    </div>
    
    <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>
    
</body>
</html>

index.html

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

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 模板的所有功能,尤其是 模板继承功能。所有这些功能都可以在template 模块 的代码文档中了解到。(其中一些功能是在 web 模块中实现的,例如 UIModules

tornado cookie

Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于RFC2109和2965都已废弃,最新取代的规范是RFC6265。(可以叫做浏览器缓存)

1、cookie的基本操作

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
   
import tornado.ioloop
import tornado.web
   
   
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        print(self.cookies)              # 获取所有的cookie
        self.set_cookie('k1','v1')       # 设置cookie
        print(self.get_cookie('k1'))     # 获取指定的cookie
        self.write("Hello, world")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
])
   
   
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

2、加密cookie(签名)

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
import tornado.ioloop
import tornado.web
    
class MainHandler(tornado.web.RequestHandler):
    def get(self):
         if not self.get_secure_cookie("mycookie"):             # 获取带签名的cookie
             self.set_secure_cookie("mycookie", "myvalue")      # 设置带签名的cookie
             self.write("Your cookie was not set yet!")
         else:
             self.write("Your cookie was set!")
application = tornado.web.Application([
    (r"/index", MainHandler),
])
   
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

签名Cookie的本质是:

写cookie过程:

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

读cookie过程:

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

用cookie做简单的自定义用户验证,下面会写一个绝对牛逼的自定义session用户验证

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/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 == '张岩林' and password == '123':
            self.set_secure_cookie('login_user', '张岩林')
            self.redirect('/')
        else:
            self.render('login.html', **{'status': '用户名或密码错误'})
 
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'zhangyanlinhaoshuai',
}
 
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)
 
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

自定义验证登录

3、JavaScript操作Cookie

由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie。

/*
设置cookie,指定秒数过期,
name表示传入的key,
value表示传入相对应的value值,
expires表示当前日期在加5秒过期
 */

function setCookie(name,value,expires){
    var temp = [];
    var current_date = new Date();
    current_date.setSeconds(current_date.getSeconds() + 5);
    document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}

注:jQuery中也有指定的插件 jQuery Cookie 专门用于操作cookie,猛击这里

4、自定义session

本来这想新开一个帖子,但是还是把代码贴在这吧,有用到session验证的时候直接复制拿走就好

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop

container = {}
class Session:
    def __init__(self, handler):
        self.handler = handler
        self.random_str = None

    def __genarate_random_str(self):
        import hashlib
        import time
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = obj.hexdigest()
        return random_str

    def __setitem__(self, key, value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        # 判断,请求的用户是否已有随机字符串
        if not self.random_str:
            random_str = self.handler.get_cookie('__session__')
            if not random_str:
                random_str = self.__genarate_random_str()
                container[random_str] = {}
            else:
                # 客户端有随机字符串
                if random_str in container.keys():
                    pass
                else:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
            self.random_str = random_str # self.random_str = asdfasdfasdfasdf

        container[self.random_str][key] = value
        self.handler.set_cookie("__session__", self.random_str)

    def __getitem__(self, key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__session__")
        if not random_str:
            return None
        # 客户端有随机字符串
        user_info_dict = container.get(random_str,None)
        if not user_info_dict:
            return None
        value = user_info_dict.get(key, None)
        return value


class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = Session(self)

自定义session

XSS攻击和CSRF请求伪造

XSS

跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。

tornado中已经为我们给屏蔽了XSS,但是当我们后端向前端写前端代码的时候传入浏览器是字符串,而不是形成代码格式。所以就需要一个反解,在传入模板语言中前面加一个raw,例如{{ raw zhangyanlin }},这样通俗的讲可能不太懂,写一段代码,可能就懂了

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

class IndexHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/')
        script = '''
            <script>
                function Jump(baseUrl,ths){
                    var val = ths.previousElementSibling.value;
                    if (val.trim().length > 0){
                        location.href = baseUrl + val;
                    }
                }
            </script>
        '''
        self.render('index.html',jump=jump,script=script)  #传入两个前端代码的字符串

start.py

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .pager a{
            display: inline-block;
            padding: 5px;
            margin: 3px;
            background-color: #00a2ca;
        }
        .pager a.active{
            background-color: #0f0f0f;
            color: white;
        }
    </style>
</head>
<body>
    <div class="pager">
        {% raw jump %}
        {% raw script%}
    </div>
</body>
</html>    

index.html

CSRF

CSRF(Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
当前防范 XSRF 的一种通用的方法,是对每一个用户都记录一个无法预知的 cookie 数据,然后要求所有提交的请求中都必须带有这个 cookie 数据。如果此数据不匹配 ,那么这个请求就可能是被伪造的。

Tornado 有内建的 XSRF 的防范机制,要使用此机制,你需要在应用配置中加上 xsrf_cookies 设定:xsrf_cookies=True,再来写一段代码,来表示一下:

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.web
import tornado.ioloop

class CsrfHandler(tornado.web.RequestHandler):

    def get(self, *args, **kwargs):
        self.render('csrf.html')

    def post(self, *args, **kwargs):
        self.write('张岩林已经收到客户端发的请求伪造')


settings = {
    'template_path':'views',
    'static_path':'statics',
    'xsrf_cokkies':True,        # 重点在这里,往这里看
}

application = tornado.web.Application([
    (r'/csrf',CsrfHandler)
],**settings)

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

start.py

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/csrf" method="post">
        {% raw xsrf_form_html() %}
        <p><input name="user" type="text" placeholder="用户"/></p>
        <p><input name='pwd' type="text" placeholder="密码"/></p>
        <input type="submit" value="Submit" />
        <input type="button" value="Ajax CSRF" onclick="SubmitCsrf();" />
    </form>
    
    <script src="/statics/jquery-1.12.4.js"></script>
    <script type="text/javascript">

        function ChangeCode() {
            var code = document.getElementById('imgCode');
            code.src += '?';
        }
        function getCookie(name) {
            var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
            return r ? r[1] : undefined;
        }

        function SubmitCsrf() {
            var nid = getCookie('_xsrf');
            $.post({
                url: '/csrf',
                data: {'k1': 'v1',"_xsrf": nid},
                success: function (callback) {
                    // Ajax请求发送成功有,自动执行
                    // callback,服务器write的数据 callback=“csrf.post”
                    console.log(callback);
                }
            });
        }
    </script>
</body>
</html>

csrf.html

简单来说就是在form验证里面生成了一段类似于自己的身份证号一样,携带着他来访问网页

tornado上传文件

上传文件这块可以分为两大类,第一类是通过form表单验证进行上传,还有一类就是通过ajax上传,下面就来介绍一下这两类

1、form表单上传文件

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

 #!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.web
import tornado.ioloop
import os

class IndexHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        self.render('index.html')

    def post(self, *args, **kwargs):
        file_metas = self.request.files["filename"]     # 获取文件信息
        for meta in file_metas:                         
            file_name = meta['filename']                # 获得他的文件名字
            file_names = os.path.join('static','img',file_name)
            with open(file_names,'wb') as up:           # 打开本地一个文件
                up.write(meta['body'])                  # body就是文件内容,把他写到本地

settings = {
    'template_path':'views',
    'static_path':'static',
    'static_url_prefix': '/statics/',
}

application = tornado.web.Application([
    (r'/index',IndexHandler)
],**settings)

if __name__ == '__main__':
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

start.py

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件</title>
</head>
<body>
    <form action="/index" method="post" enctype="multipart/form-data">
        <input type="file" name = "filename">
        <input type="submit" value="提交">
    </form>
</body>
</html>

index.html

2、ajax上传文件

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html>
<head lang= "en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >
        <div id="main">
            <input name="filename" id="my_file"  type="file" />
            <input type="button" name="action" value="Upload" onclick="redirect()"/>
            <iframe id='my_iframe' name='my_iframe' src=""  class="hide"></iframe>
        </div>
    </form>

    <script>
        function redirect(){
            document.getElementById('my_iframe').onload = Testt;
            document.getElementById('my_form').target = 'my_iframe';
            document.getElementById('my_form').submit();

        }
        
        function Testt(ths){
            var t = $("#my_iframe").contents().find("body").text();
            console.log(t);
        }
    </script>
</body>
</html>

HTML iframe

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="file" id="img" />
    <input type="button" onclick="UploadFile();" value="提交"/>

    <script src="/statics/jquery-1.12.4.js"></script>
    <script>
        function UploadFile(){
            var fileObj = $("#img")[0].files[0];
            var form = new FormData();
            form.append("filename", 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>

Jquery 上传

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <input type="file" id="img" />
    <input type="button" onclick="UploadFile();" value="提交" />
    <script>
        function UploadFile(){
            var fileObj = document.getElementById("img").files[0];

            var form = new FormData();
            form.append("filename", fileObj);

            var xhr = new XMLHttpRequest();
            xhr.open("post", '/index', true);
            xhr.send(form);
        }
    </script>
</body>
</html>

XML提交

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.web
import tornado.ioloop
import os

class IndexHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        self.render('index.html')

    def post(self, *args, **kwargs):
        file_metas = self.request.files["filename"]     # 获取文件信息
        for meta in file_metas:
            file_name = meta['filename']                # 获得他的文件名字
            file_names = os.path.join('static','img',file_name)
            with open(file_names,'wb') as up:           # 打开本地一个文件
                up.write(meta['body'])                  # body就是文件内容,把他写到本地

settings = {
    'template_path':'views',
    'static_path':'static',
    'static_url_prefix': '/statics/',
}

application = tornado.web.Application([
    (r'/index',IndexHandler)
],**settings)

if __name__ == '__main__':
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

start.py

注:下面所有的实例用相同的python代码都能实现,只需要改前端代码,python代码文件名为start.py

tornado 生成随机验证码

用python生成随机验证码需要借鉴一个插件,和一个io模块,实现起来也非常容易,当然也需要借鉴session来判断验证码是否错误,下面写一段用户登录验证带验证码的,再看下效果,插件必须和执行文件必须放在更目录下

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop

container = {}
class Session:
    def __init__(self, handler):
        self.handler = handler
        self.random_str = None

    def __genarate_random_str(self):
        import hashlib
        import time
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = obj.hexdigest()
        return random_str

    def __setitem__(self, key, value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        # 判断,请求的用户是否已有随机字符串
        if not self.random_str:
            random_str = self.handler.get_cookie('__session__')
            if not random_str:
                random_str = self.__genarate_random_str()
                container[random_str] = {}
            else:
                # 客户端有随机字符串
                if random_str in container.keys():
                    pass
                else:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
            self.random_str = random_str # self.random_str = asdfasdfasdfasdf

        container[self.random_str][key] = value
        self.handler.set_cookie("__session__", self.random_str)

    def __getitem__(self, key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__session__")
        if not random_str:
            return None
        # 客户端有随机字符串
        user_info_dict = container.get(random_str,None)
        if not user_info_dict:
            return None
        value = user_info_dict.get(key, None)
        return value


class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = Session(self)


class LoginHandler(BaseHandler):
    def get(self, *args, **kwargs):
        self.render('login.html' ,state = "")

    def post(self, *args, **kwargs):
        username = self.get_argument('username')
        password = self.get_argument('password')
        code =self.get_argument('code')
        check_code = self.session['CheckCode']
        if username =="zhangyanlin" and password == "123" and code.upper() == check_code.upper():
            self.write("登录成功")
        else:
            self.render('login.html',state = "验证码错误")

class CheckCodeHandler(BaseHandler):
    def get(self, *args, **kwargs):
        import io
        import check_code
        mstream = io.BytesIO()
        img,code = check_code.create_validate_code()
        img.save(mstream,"GIF")
        self.session['CheckCode'] =code
        self.write(mstream.getvalue())


settings = {
    'template_path':'views',
    'cookie_secret': "asdasd",
}

application = tornado.web.Application([
    (r'/login',LoginHandler),
    (r'/check_code',CheckCodeHandler)
],**settings)

if __name__ == '__main__':
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

start.py

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>验证码</title>
</head>
<body>
    <form action="/login" method="post">
        <p>用户名: <input type="text" name="username"> </p>
        <p>密码: <input type="password" name="password"> </p>
        <p>验证码: <input type="text" name="code"><img src="/check_code" onclick="ChangeCode();" id = "checkcode"></p>
        <input type="submit" value="submit"> <span>{{state}}</span>
    </form>
<script type="text/javascript">  //当点击图片的时候,会刷新图片,这一段代码就可以实现
    function ChangeCode() {
        var code = document.getElementById('checkcode');
        code.src += "?";
    }
</script>
</body>
</html>

login.html

效果图如下:

Python学习笔记_进阶篇(一)_浅析tornado web框架,Python,python,学习,笔记

插件下载地址:猛击这里文章来源地址https://www.toymoban.com/news/detail-664357.html

到了这里,关于Python学习笔记_进阶篇(一)_浅析tornado web框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python学习之路-爬虫进阶:爬虫框架运行

    安装框架的目的 利用setup.py将框架安装到python环境中,在编写爬虫时候,作为第三方模块来调用 框架安装第一步:完成 setup.py 的编写 以下代码相当于一个模板,只用更改name字段出,改为对应的需要安装的模块名称就可以,比如这里是:scrapy_plus 将setup.py文件放到scrapy_plus的

    2024年02月19日
    浏览(44)
  • 【0基础入门Python Web笔记】四、python 之计算器的进阶之路

    一、python 之基础语法、基础数据类型、复合数据类型及基本操作 二、python 之逻辑运算和制流程语句 三、python 之函数以及常用内置函数 现在的实战需求: 计算出任意两个数字的加法之和 可以通过一下代码直接计算出a和b之和: 以上代码只需要修改a和b的值,就可以轻松计算

    2024年02月11日
    浏览(41)
  • streamlit (python构建web可视化框架)笔记

    pip install streamlit 创建一个python文件 demo.py ,使用命令行运行在浏览器上 streamlit run demo.py 。 官方文档 Streamlit documentation 中文文档 可参考博客1-专栏 streamlit 提供了基于 python 的 web应用程序框架 ,以高效灵活的方式 可视化数据 。主要功能 streamlit 对数据可视化渲染,表格、地

    2023年04月26日
    浏览(44)
  • 【Python】Streamlit库学习:一款好用的Web框架

    ✨Streamlit是一个基于tornado框架的快速搭建Web应用的Python库,封装了大量常用组件方法,支持大量数据表、图表等对象的渲染,支持网格化、响应式布局。简单来说,可以让不了解前端的人搭建网页。 相比于同类产品PyWebIO,Streamlit的功能更加全面一些。 官方文档:https://doc

    2024年02月01日
    浏览(46)
  • Python学习笔记_进阶篇(二)_django知识(一)

    本章简介: Django 简介 Django 基本配置 Django url Django view Django 模板语言 Django Form Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的软件设计模式,即模型M,视图V和控制器C。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的。并于

    2024年02月12日
    浏览(51)
  • Python学习笔记_进阶篇(四)_django知识(三)

    本章内容: Django 发送邮件 Django cookie Django session Django CSRF 我们常常会用到一些发送邮件的功能,比如有人提交了应聘的表单,可以向HR的邮箱发邮件,这样,HR不看网站就可以知道有人在网站上提交了应聘信息。今天我们尝试用django发送邮件做尝试 1、配置相关参数settings 往

    2024年02月11日
    浏览(51)
  • Python学习笔记_进阶篇(三)_django知识(二)

    本章内容 Django model django默认支持sqlite,mysql, oracle,postgresql数据库。 1 sqlite django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 引擎名称:django.db.backends.sqlite3 2mysql 引擎名称:django.db.backends.mysql 1、配置文件中sqlite 2、配置文件中mysql 注:由于Django内部连接MySQL时使用的

    2024年02月12日
    浏览(43)
  • web自动化框架:selenium学习使用操作大全(Python版)

    Selenium需要浏览器驱动程序才能与所选浏览器交互。例如,Firefox需要安装geckodriver。确保它在PATH中。 主流浏览器驱动下载地址如下: 浏览器 驱动名称 打开方式及注意事项 地址 Chrome chromedriver driver = webdriver.Chrome() 下载浏览器对应版本的chromedriver.exe 一定要创建对象,不然打

    2024年02月11日
    浏览(44)
  • 【Python】Web学习笔记_flask(3)——上传文件

    用GET、POST请求上传图片并呈现出来 首先还是创建文件上传的模板 然后需要定义几个函数: upload():路由函数,接收GET请求时,显示模板文件内容,接收post请求时,上传图片 allowed_file():检测上传的文件是否满足设置的类型 random_file():为上传的文件重新创建随机的不重复文

    2024年02月14日
    浏览(47)
  • 【Python】Web学习笔记_flask(4)——钩子函数

    钩子函数可以用来注册在请求处理的不同阶段执行出 Flask的请求钩子指的是在执行视图函数前后执行的一些函数, 之前是有4种,但是  before_first_request已经被删除了,使用时会报错 before_request:在每次请求前执行,比如校验权限,也可以用来记录用户最后的在线时间 after_r

    2024年02月14日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包