tornado web 框架的認識

tornado 簡介

1,概述

Tornado就是咱們在 FriendFeed 的 Web 服務器及其經常使用工具的開源版本。Tornado 和如今的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。得利於其 非阻塞的方式和對epoll的運用,Tornado 每秒能夠處理數以千計的鏈接,所以 Tornado 是實時 Web 服務的一個 理想框架。咱們開發這個 Web 服務器的主要目的就是爲了處理 FriendFeed 的實時功能 ——在 FriendFeed 的應用裏每個活動用戶都會保持着一個服務器鏈接。(關於如何擴容 服務器,以處理數以千計的客戶端的鏈接的問題,請參閱The C10K problem)
javascript

Tornado表明嵌入實時應用中最新一代的開發和執行環境。 Tornado 包含三個完整的部分:css

     (1)、Tornado系列工具, 一套位於主機或目標機上強大的交互式開發工具和使用程序;html

     (2)、VxWorks 系統, 目標板上高性能可擴展的實時操做系統;前端

     (3)、可選用的鏈接主機和目標機的通信軟件包 如以太網、串行線、在線仿真器或ROM仿真器java

2,tornado特色

Tornado的獨特之處在於其全部開發工具可以使用在應用開發的任意階段以及任何檔次的硬件資源上。並且,完整集的Tornado工具可使開發人員徹底不用考慮與目標鏈接的策略或目標存儲區大小。Tornado 結構的專門設計爲開發人員和第三方工具廠商提供了一個開放環境。已有部分應用程序接口能夠利用並附帶參考書目,內容從開發環境接口到鏈接實現。Tornado包括強大的開發和調試工具,尤爲適用於面對大量問題的嵌入式開發人員。這些工具包括C和C++源碼級別的調試器,目標和工具管理,系統目標跟蹤,內存使用分析和自動配置. 另外,全部工具能很方便地同時運行,很容易增長和交互式開發。python

3,tornado模塊索引

最重要的一個模塊是web, 它就是包含了 Tornado 的大部分主要功能的 Web 框架。其它的模塊都是工具性質的, 以便讓 web 模塊更加有用 後面的 Tornado 攻略 詳細講解了 web 模塊的使用方法。jquery

主要模塊ios

  • web - FriendFeed 使用的基礎 Web 框架,包含了 Tornado 的大多數重要的功能
  • escape - XHTML, JSON, URL 的編碼/解碼方法
  • database - 對 MySQLdb 的簡單封裝,使其更容易使用
  • template - 基於 Python 的 web 模板系統
  • httpclient - 非阻塞式 HTTP 客戶端,它被設計用來和 web 及 httpserver 協同工做
  • 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

二、先寫一個入門級的代碼吧,相信你們都能看懂,聲明: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 端口git

第二步:瀏覽器客戶端訪問 /index  -->  http://127.0.0.1:8080/indexgithub

第三步:服務器接受請求,並交由對應的類處理該請求

第四步:類接受到請求以後,根據請求方式(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對應的是一個類

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 __auth__ = "dushen"
 4  
 5 import tornado.web  6 import tornado.ioloop  7  
 8 class IndexHandler(tornado.web.RequestHandler):  9  
10     def get(self, *args, **kwargs): 11         self.write("Hello World, My name is 賭神") 12  
13 class LoginHandler(tornado.web.RequestHandler): 14  
15     def get(self, *args, **kwargs): 16         self.write("<input type = 'text'>") 17  
18 class RegisterHandler(tornado.web.RequestHandler): 19  
20     def get(self, *args, **kwargs): 21         self.write("<input type = 'password'>") 22  
23 application = tornado.web.Application([ 24     (r'/index/(?P<page>\d*)',IndexHandler),  # 基礎正則路由
25     (r'/login',LoginHandler), 26     (r'/register',RegisterHandler), 27 ])

觀察全部的網頁的內容,下面都有分頁,當點擊下一頁後面的數字也就跟着變了,這種就能夠用基礎正則路由來作,下面我來給你們下一個網頁分頁的案例吧

  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 __auth__ = "zhangyanlin"
  4 
  5 import tornado.web
  6 import tornado.ioloop
  7 
  8 LIST_INFO = [
  9     {'username':'zhangyanlin','email':'133@164.com'}
 10 ]
 11 for i in range(200):
 12     temp = {'username':str(i)+"zhang",'email':str(i)+"@163.com"}
 13     LIST_INFO.append(temp)
 14 
 15 
 16 class Pagenation:
 17 
 18     def __init__(self,current_page,all_item,base_url):  #當前頁 內容總數 目錄
 19         try:
 20             page = int(current_page)
 21         except:
 22             page = 1
 23         if page < 1:
 24             page = 1
 25 
 26         all_page,c = divmod(all_item,5)
 27         if c > 0:
 28             all_page +=1
 29 
 30         self.current_page = page
 31         self.all_page = all_page
 32         self.base_url = base_url
 33 
 34     @property
 35     def start(self):
 36         return (self.current_page - 1) * 5
 37 
 38     @property
 39     def end(self):
 40         return self.current_page * 5
 41 
 42     def string_pager(self):
 43         list_page = []
 44         if self.all_page < 11:
 45             s = 1
 46             t = self.all_page + 1
 47         else:
 48             if self.current_page < 6:
 49                 s = 1
 50                 t = 12
 51             else:
 52                 if (self.current_page + 5) < self.all_page:
 53                     s = self.current_page-5
 54                     t = self.current_page + 6
 55                 else:
 56                     s = self.all_page - 11
 57                     t = self.all_page +1
 58 
 59         first = '<a href = "/index/1">首頁</a>'
 60         list_page.append(first)
 61         # 當前頁
 62         if self.current_page == 1:
 63             prev = '<a href = "javascript:void(0):">上一頁</a>'
 64         else:
 65             prev = '<a href = "/index/%s">上一頁</a>'%(self.current_page-1,)
 66         list_page.append(prev)
 67 
 68         #頁碼
 69         for p in range(s,t):
 70             if p== self.current_page:
 71                 temp = '<a class = "active" href = "/index/%s">%s</a>'%(p,p)
 72             else:
 73                 temp = '<a href = "/index/%s">%s</a>' % (p, p)
 74             list_page.append(temp)
 75 
 76 
 77 
 78         # 尾頁
 79         if self.current_page == self.all_page:
 80             nex = '<a href = "javascript:void(0):">下一頁</a>'
 81         else:
 82             nex = '<a href = "/index/%s">下一頁</a>' % (self.current_page + 1,)
 83         list_page.append(nex)
 84 
 85         last = '<a href = "/index/%s">尾頁</a>'%(self.all_page)
 86         list_page.append(last)
 87 
 88 
 89         #跳轉
 90         jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/')
 91         script = '''
 92             <script>
 93                 function Jump(baseUrl,ths){
 94                     var val = ths.previousElementSibling.value;
 95                     if (val.trim().length > 0){
 96                         location.href = baseUrl + val;
 97                     }
 98                 }
 99             </script>
100         '''
101         list_page.append(jump)
102         list_page.append(script)
103         str_page = "".join(list_page)
104 
105         return str_page
106 
107 class IndexHandler(tornado.web.RequestHandler):
108 
109     def get(self, page):
110         obj = Pagenation(page,len(LIST_INFO),'/index/')
111         current_list = LIST_INFO[obj.start:obj.end]
112         str_page = obj.string_pager()
113         self.render('index.html', list_info=current_list, current_page=obj.current_page, str_page=str_page)
114 
115 application = tornado.web.Application([
116     (r'/index/(?P<page>\d*)',IndexHandler)
117 
118 ])
119 
120 
121 if __name__ == "__main__":
122     application.listen(8080)
123     tornado.ioloop.IOLoop.instance().start()
View Code
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <style>
 7         .pager a{
 8             display: inline-block;
 9             padding: 5px 6px;
10             margin: 10px 3px;
11             border: 1px solid #2b669a;
12             text-decoration:none;
13 
14         }
15         .pager a.active{
16             background-color: #2b669a;
17             color: white;
18         }
19     </style>
20 </head>
21 <body>
22     <h3>顯示數據</h3>
23     <table border="1">
24         <thead>
25             <tr>
26                 <th>用戶名</th>
27                 <th>郵箱</th>
28             </tr>
29         </thead>
30         <tbody>
31             {% for line in list_info %}
32                 <tr>
33                     <td>{{line['username']}}</td>
34                     <td>{{line['email']}}</td>
35                 </tr>
36             {% end %}
37         </tbody>
38     </table>
39     <div class="pager">
40         {% raw str_page %}
41     </div>
42 </body>
43 </html>
前端html文件

注:兩個文件必須放在同一個文件夾下,中間前端代碼中有用到XSS攻擊和模板語言,這兩個知識點下面會詳細解釋

 tornado模板引擎

Tornao中的模板語言和django中相似,模板引擎將模板文件載入內存,而後將數據嵌入其中,最終獲取到一個完整的字符串,再將字符串返回給請求者。

Tornado 的模板支持「控制語句」和「表達語句」,控制語句是使用 {% 和 %} 包起來的 例如 {% if len(items) > 2 %}。表達語句是使用 {{ 和 }} 包起來的,例如 {{ items[0] }}

控制語句和對應的 Python 語句的格式基本徹底相同。咱們支持 ifforwhile 和 try,這些語句邏輯結束的位置須要用 {% end %} 作標記。還經過 extends 和 block 語句實現了模板繼承。這些在 template 模塊 的代碼文檔中有着詳細的描述。

注:在使用模板前須要在setting中設置模板路徑:"template_path" : "views"

 1 settings = {  2     'template_path':'views',             #設置模板路徑,設置完能夠把HTML文件放置views文件夾中
 3     'static_path':'static',              # 設置靜態模板路徑,設置完能夠把css,JS,Jquery等靜態文件放置static文件夾中
 4     'static_url_prefix': '/sss/',        #導入時候須要加上/sss/,例如<script src="/sss/jquery-1.9.1.min.js"></script>
 5     'cookie_secret': "asdasd",           #cookie生成祕鑰時候需提早生成隨機字符串,須要在這裏進行渲染
 6     'xsrf_cokkies':True,                 #容許CSRF使用
 7 }  8 application = tornado.web.Application([  9     (r'/index',IndexHandler), 10 ],**settings)                           #須要在這裏加載

 一、模板語言基本使用for循環,if..else使用,自定義UIMethod以UIModule

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import tornado.ioloop
 4 import tornado.web
 5 import uimodule as md
 6 import uimethod as mt
 7 
 8 INPUT_LIST = []
 9 class MainHandler(tornado.web.RequestHandler):
10     def get(self, *args, **kwargs):
11         name = self.get_argument('xxx',None)
12         if name:
13             INPUT_LIST.append(name)
14         self.render("index.html",npm = "NPM88888",xxoo = INPUT_LIST)
15 
16     def post(self, *args, **kwargs):
17         name = self.get_argument('xxx')
18         INPUT_LIST.append(name)
19         self.render("index.html", npm = "NPM88888", xxoo = INPUT_LIST)
20         # self.write("Hello, World!!!")
21 
22 settings = {
23     'template_path':'tpl',  # 模板路徑的配置
24     'static_path':'statics',  # 靜態文件路徑的配置
25     'ui_methods':mt,        # 自定義模板語言
26     'ui_modules':md,        # 自定義模板語言
27 }
28 
29 #路由映射,路由系統
30 application = tornado.web.Application([
31     (r"/index",MainHandler),
32 ],**settings)
33 
34 
35 if __name__ == "__main__":
36     # 運行socket
37     application.listen(8000)
38     tornado.ioloop.IOLoop.instance().start()
start.py
1 from tornado.web import UIModule
2 from tornado import escape
3 
4 class custom(UIModule):
5 
6     def render(self, *args, **kwargs):
7         return "張巖林"
uimodule
1 def func(self,arg):
2     return arg.lower()
uimethod
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link type="text/css" rel="stylesheet" href="static/commons.css">
 7 </head>
 8 <body>
 9     <script src="static/zhang.js"></script>
10     <h1>Hello world</h1>
11     <h1>My name is zhangyanlin</h1>
12     <h1>輸入內容</h1>
13     <form action="/index" method="post">
14         <input type="text" name="xxx">
15         <input type="submit" value="提交">
16     </form>
17     <h1>展現內容</h1>
18     <h3>{{ npm }}</h3>
19     <h3>{{ func(npm)}}</h3>
20     <h3>{% module custom() %}</h3>
21     <ul>
22         {% for item in xxoo %}
23             {% if item == "zhangyanlin" %}
24                 <li style="color: red">{{item}}</li>
25             {% else %}
26                 <li>{{item}}</li>
27             {% end %}
28         {% end %}
29     </ul>
30 </body>
31 </html>
index.html

二、母板繼承

(1)、至關於python的字符串格式化同樣,先定義一個佔位符

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 5     <title>帥哥</title>
 6     <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
 7     {% block CSS %}{% end %}
 8 </head>
 9 <body>
10 
11     <div class="pg-header">
12 
13     </div>
14     
15     {% block RenderBody %}{% end %}
16    
17     <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>
18     
19     {% block JavaScript %}{% end %}
20 </body>
21 </html>
layout.html

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

 1 {% extends 'layout.html'%}
 2 {% block CSS %}
 3     <link href="{{static_url("css/index.css")}}" rel="stylesheet" />
 4 {% end %}
 5 
 6 {% block RenderBody %}
 7     <h1>Index</h1>
 8 
 9     <ul>
10     {%  for item in li %}
11         <li>{{item}}</li>
12     {% end %}
13     </ul>
14 
15 {% end %}
16 
17 {% block JavaScript %}
18     
19 {% end %}
index.html

三、導入內容

1 <div>
2     <ul>
3         <li>張巖林帥</li>
4         <li>張巖林很帥</li>
5         <li>張巖林很很帥</li>
6     </ul>
7 </div>
View Code
 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 5     <title>張巖林</title>
 6     <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
 7 </head>
 8 <body>
 9 
10     <div class="pg-header">
11         {% include 'header.html' %}
12     </div>
13     
14     <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>
15     
16 </body>
17 </html>
View Code
 1 在模板中默認提供了一些函數、字段、類以供模板使用:  2  
 3 escape: tornado.escape.xhtml_escape 的別名  4 xhtml_escape: tornado.escape.xhtml_escape 的別名  5 url_escape: tornado.escape.url_escape 的別名  6 json_encode: tornado.escape.json_encode 的別名  7 squeeze: tornado.escape.squeeze 的別名  8 linkify: tornado.escape.linkify 的別名  9 datetime: Python 的 datetime 模組 10 handler: 當前的 RequestHandler 對象 11 request: handler.request 的別名 12 current_user: handler.current_user 的別名 13 locale: handler.locale 的別名 14 _: handler.locale.translate 的別名 15 static_url: for handler.static_url 的別名 16 xsrf_form_html: handler.xsrf_form_html 的別名

當你製做一個實際應用時,你會須要用到 Tornado 模板的全部功能,尤爲是 模板繼承功能。全部這些功能均可以在template 模塊 的代碼文檔中瞭解到。(其中一些功能是在 web 模塊中實現的,例如 UIModules

tornado cookie

 Cookie,有時也用其複數形式Cookies,指某些網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(一般通過加密)。定義於RFC2109和2965都已廢棄,最新取代的規範是RFC6265。(能夠叫作瀏覽器緩存)

一、cookie的基本操做

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3    
 4 import tornado.ioloop  5 import tornado.web  6    
 7    
 8 class MainHandler(tornado.web.RequestHandler):  9     def get(self): 10         print(self.cookies)              # 獲取全部的cookie
11         self.set_cookie('k1','v1')       # 設置cookie
12         print(self.get_cookie('k1'))     # 獲取指定的cookie
13         self.write("Hello, world") 14    
15 application = tornado.web.Application([ 16     (r"/index", MainHandler), 17 ]) 18    
19    
20 if __name__ == "__main__": 21     application.listen(8888) 22     tornado.ioloop.IOLoop.instance().start()

二、加密cookie(簽名)

Cookie 很容易被惡意的客戶端僞造。加入你想在 cookie 中保存當前登錄用戶的 id 之類的信息,你須要對 cookie 做簽名以防止僞造。Tornado 經過 set_secure_cookie 和 get_secure_cookie 方法直接支持了這種功能。 要使用這些方法,你須要在建立應用時提供一個密鑰,名字爲 cookie_secret。 你能夠把它做爲一個關鍵詞參數傳入應用的設置中

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3    
 4 import tornado.ioloop  5 import tornado.web  6     
 7 class MainHandler(tornado.web.RequestHandler):  8     def get(self):  9          if not self.get_secure_cookie("mycookie"):             # 獲取帶簽名的cookie
10              self.set_secure_cookie("mycookie", "myvalue")      # 設置帶簽名的cookie
11              self.write("Your cookie was not set yet!") 12          else: 13              self.write("Your cookie was set!") 14 application = tornado.web.Application([ 15     (r"/index", MainHandler), 16 ]) 17    
18 if __name__ == "__main__": 19     application.listen(8888) 20     tornado.ioloop.IOLoop.instance().start()

簽名Cookie的本質是:

寫cookie過程: 將值進行base64加密 對除值之外的內容進行簽名,哈希算法(沒法逆向解析) 拼接 簽名 + 加密值 讀cookie過程: 讀取 簽名 + 加密值 對簽名進行驗證 base64解密,獲取值內容

用cookie作簡單的自定義用戶驗證,下面會寫一個絕對牛逼的自定義session用戶驗證

 1 #!/usr/bin/python
 2 # -*- coding: UTF-8 -*-
 3 
 4 
 5 import tornado.web
 6 import tornado.ioloop
 7 container = {}
 8 # container = {
 9 #     # "第一我的的隨機字符串":{},
10 #     # "第一我的的隨機字符串":{'k1': 111, 'parents': '你'},
11 # }
12 
13 class Session:
14     def __init__(self, handler):
15         self.handler = handler
16         self.random_str = None
17 
18     def __genarate_random_str(self):
19         import hashlib
20         import time
21         obj = hashlib.md5()
22         obj.update(bytes(str(time.time()), encoding='utf-8'))
23         random_str = obj.hexdigest()
24         return random_str
25 
26     def __setitem__(self, key,value):
27         # 在container中加入隨機字符串
28         # 定義專屬於本身的數據
29         # 在客戶端中寫入隨機字符串
30         # 判斷,請求的用戶是否已有隨機字符串
31         if not self.random_str:
32             random_str = self.handler.get_cookie('__kakaka__')
33             if not random_str:
34                 random_str = self.__genarate_random_str()
35                 container[random_str] = {}
36             else:
37                 # 客戶端有隨機字符串
38                 if random_str in container.keys():
39                     pass
40                 else:
41                     random_str = self.__genarate_random_str()
42                     container[random_str] = {}
43             self.random_str = random_str # self.random_str = asdfasdfasdfasdf
44 
45         container[self.random_str][key] = value
46         self.handler.set_cookie("__kakaka__", self.random_str)
47 
48     def __getitem__(self,key):
49         # 獲取客戶端的隨機字符串
50         # 從container中獲取專屬於個人數據
51         #  專屬信息【key】
52         random_str =  self.handler.get_cookie("__kakaka__")
53         if not random_str:
54             return None
55         # 客戶端有隨機字符串
56         user_info_dict = container.get(random_str,None)
57         if not user_info_dict:
58             return None
59         value = user_info_dict.get(key, None)
60         return value
61 class BaseHandler(tornado.web.RequestHandler):
62     def initialize(self):
63         self.session = Session(self)
64 
65 class IndexHandler(BaseHandler):
66     def get(self):
67         if self.get_argument('u',None) in ['alex','eric']:
68             self.session['is_login'] = True
69             self.session['name'] = self.get_argument('u',None)
70 
71         else:
72             self.write('請登陸')
73 
74 class ManagerHandler(BaseHandler):
75     def get(self):
76         s = Session(self)
77         val = self.session['is_login']
78         if val:
79             self.write(self.session['name'])
80         else:
81             self.write('失敗')
自定義sesson實現用戶登陸

三、JavaScript操做Cookie

因爲Cookie保存在瀏覽器端,因此在瀏覽器端也可使用JavaScript來操做Cookie。

 

 1 /*
 2 設置cookie,指定秒數過時,  3 name表示傳入的key,  4 value表示傳入相對應的value值,  5 expires表示當前日期在加5秒過時  6  */
 7 
 8 function setCookie(name,value,expires){  9     var temp = []; 10     var current_date = new Date(); 11     current_date.setSeconds(current_date.getSeconds() + 5); 12     document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString(); 13 }

注:jQuery中也有指定的插件 jQuery Cookie 專門用於操做cookie,猛擊這裏

自定義session

cookie 和sesson的區別

1,cookie數據存放在客戶的瀏覽器上,sesson數據存放在服務器上。

2,cookie不是很安全,別人能夠分析存放本地的cookie並進行cookie欺騙,考慮到安全應當使用session

3,session會在必定的時間保存在服務器上。當訪問量增多會比較粘你服務器的性能 考慮到減小服務器性能方面應當使用cookie

4,單個cookie保存的數據不能超過4k 橫多瀏覽器都限制一個站點包村20個cookie

5,因此我的建議,將登陸的信息的等重要的信息存放在session,其餘信息如需保留能夠存放在cookie中

 

原本這想新開一個帖子,可是仍是把代碼貼在這吧,有用到session驗證的時候直接複製拿走就好

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import tornado.web
 4 import tornado.ioloop
 5 
 6 container = {}
 7 class Session:
 8     def __init__(self, handler):
 9         self.handler = handler
10         self.random_str = None
11 
12     def __genarate_random_str(self):
13         import hashlib
14         import time
15         obj = hashlib.md5()
16         obj.update(bytes(str(time.time()), encoding='utf-8'))
17         random_str = obj.hexdigest()
18         return random_str
19 
20     def __setitem__(self, key, value):
21         # 在container中加入隨機字符串
22         # 定義專屬於本身的數據
23         # 在客戶端中寫入隨機字符串
24         # 判斷,請求的用戶是否已有隨機字符串
25         if not self.random_str:
26             random_str = self.handler.get_cookie('__session__')
27             if not random_str:
28                 random_str = self.__genarate_random_str()
29                 container[random_str] = {}
30             else:
31                 # 客戶端有隨機字符串
32                 if random_str in container.keys():
33                     pass
34                 else:
35                     random_str = self.__genarate_random_str()
36                     container[random_str] = {}
37             self.random_str = random_str # self.random_str = asdfasdfasdfasdf
38 
39         container[self.random_str][key] = value
40         self.handler.set_cookie("__session__", self.random_str)
41 
42     def __getitem__(self, key):
43         # 獲取客戶端的隨機字符串
44         # 從container中獲取專屬於個人數據
45         #  專屬信息【key】
46         random_str =  self.handler.get_cookie("__session__")
47         if not random_str:
48             return None
49         # 客戶端有隨機字符串
50         user_info_dict = container.get(random_str,None)
51         if not user_info_dict:
52             return None
53         value = user_info_dict.get(key, None)
54         return value
55 
56 
57 class BaseHandler(tornado.web.RequestHandler):
58     def initialize(self):
59         self.session = Session(self)
自定義sesson

xss攻擊和csrf請求僞造

跨站腳本攻擊(Cross Site Scripting),爲不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫爲XSS。惡意攻擊者往Web頁面裏插入惡意Script代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的Script代碼會被執行,從而達到惡意攻擊用戶的特殊目的。

tornado中已經爲咱們給屏蔽了XSS,可是當咱們後端向前端寫前端代碼的時候傳入瀏覽器是字符串,而不是造成代碼格式。因此就須要一個反解,在傳入模板語言中前面加一個raw,例如{{ raw zhangyanlin }},這樣通俗的講可能不太懂,寫一段代碼,可能就懂了

 1 class IndexHandler(tornado.web.RequestHandler):
 2     def get(self, *args, **kwargs):
 3         jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/')
 4         script = '''
 5             <script>
 6                 function Jump(baseUrl,ths){
 7                     var val = ths.previousElementSibling.value;
 8                     if (val.trim().length > 0){
 9                         location.href = baseUrl + val;
10                     }
11                 }
12             </script>
13         '''
14         self.render('index.html',jump=jump,script=script)  #傳入兩個前端代碼的字符串
View Code
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="/csrf" method="post">
 9         {% raw xsrf_form_html() %}
10         <p><input name="user" type="text" placeholder="用戶"/></p>
11         <p><input name='pwd' type="text" placeholder="密碼"/></p>
12         <input type="submit" value="Submit" />
13         <input type="button" value="Ajax CSRF" onclick="SubmitCsrf();" />
14     </form>
15     
16     <script src="/statics/jquery-1.12.4.js"></script>
17     <script type="text/javascript">
18 
19         function ChangeCode() {
20             var code = document.getElementById('imgCode');
21             code.src += '?';
22         }
23         function getCookie(name) {
24             var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
25             return r ? r[1] : undefined;
26         }
27 
28         function SubmitCsrf() {
29             var nid = getCookie('_xsrf');
30             $.post({
31                 url: '/csrf',
32                 data: {'k1': 'v1',"_xsrf": nid},
33                 success: function (callback) {
34                     // Ajax請求發送成功有,自動執行
35                     // callback,服務器write的數據 callback=「csrf.post」
36                     console.log(callback);
37                 }
38             });
39         }
40     </script>
41 </body>
42 </html>
csrf

簡單來講就是在form驗證裏面生成了一段相似於本身的身份證號同樣,攜帶着他來訪問網頁

tornado上傳文件

上傳文件這塊能夠分爲兩大類,第一類是經過form表單驗證進行上傳,還有一類就是經過ajax上傳,下面就來介紹一下這兩類

 一、form表單上傳文件

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import tornado.web
 5 import tornado.ioloop
 6 import os
 7 
 8 class IndexHandler(tornado.web.RequestHandler):
 9     def get(self, *args, **kwargs):
10         self.render('index.html')
11 
12     def post(self, *args, **kwargs):
13         file_metas = self.request.files["filename"]     # 獲取文件信息
14         for meta in file_metas:                         
15             file_name = meta['filename']                # 得到他的文件名字
16             file_names = os.path.join('static','img',file_name)
17             with open(file_names,'wb') as up:           # 打開本地一個文件
18                 up.write(meta['body'])                  # body就是文件內容,把他寫到本地
19 
20 settings = {
21     'template_path':'views',
22     'static_path':'static',
23     'static_url_prefix': '/statics/',
24 }
25 
26 application = tornado.web.Application([
27     (r'/index',IndexHandler)
28 ],**settings)
29 
30 if __name__ == '__main__':
31     application.listen(8888)
32     tornado.ioloop.IOLoop.instance().start()
start.py
<!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上傳文件

 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >
 9         <div id="main">
10             <input name="filename" id="my_file"  type="file" />
11             <input type="button" name="action" value="Upload" onclick="redirect()"/>
12             <iframe id='my_iframe' name='my_iframe' src=""  class="hide"></iframe>
13         </div>
14     </form>
15 
16     <script>
17         function redirect(){
18             document.getElementById('my_iframe').onload = Testt;
19             document.getElementById('my_form').target = 'my_iframe';
20             document.getElementById('my_form').submit();
21 
22         }
23         
24         function Testt(ths){
25             var t = $("#my_iframe").contents().find("body").text();
26             console.log(t);
27         }
28     </script>
29 </body>
30 </html>
html ifeame
 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <input type="file" id="img" />
 9     <input type="button" onclick="UploadFile();" value="提交"/>
10 
11     <script src="/statics/jquery-1.12.4.js"></script>
12     <script>
13         function UploadFile(){
14             var fileObj = $("#img")[0].files[0];
15             var form = new FormData();
16             form.append("filename", fileObj);
17 
18             $.ajax({
19                 type:'POST',
20                 url: '/index',
21                 data: form,
22                 processData: false,  // tell jQuery not to process the data
23                 contentType: false,  // tell jQuery not to set contentType
24                 success: function(arg){
25                     console.log(arg);
26                 }
27             })
28         }
29     </script>
30 </body>
31 </html>
jquery 上傳
 1 <!DOCTYPE html>
 2 <html>
 3 <head lang="en">
 4     <meta charset="UTF-8">
 5     <title></title>
 6 </head>
 7 <body>
 8     <input type="file" id="img" />
 9     <input type="button" onclick="UploadFile();" value="提交" />
10     <script>
11         function UploadFile(){
12             var fileObj = document.getElementById("img").files[0];
13 
14             var form = new FormData();
15             form.append("filename", fileObj);
16 
17             var xhr = new XMLHttpRequest();
18             xhr.open("post", '/index', true);
19             xhr.send(form);
20         }
21     </script>
22 </body>
23 </html>
XML提交
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import tornado.web
 5 import tornado.ioloop
 6 import os
 7 
 8 class IndexHandler(tornado.web.RequestHandler):
 9     def get(self, *args, **kwargs):
10         self.render('index.html')
11 
12     def post(self, *args, **kwargs):
13         file_metas = self.request.files["filename"]     # 獲取文件信息
14         for meta in file_metas:
15             file_name = meta['filename']                # 得到他的文件名字
16             file_names = os.path.join('static','img',file_name)
17             with open(file_names,'wb') as up:           # 打開本地一個文件
18                 up.write(meta['body'])                  # body就是文件內容,把他寫到本地
19 
20 settings = {
21     'template_path':'views',
22     'static_path':'static',
23     'static_url_prefix': '/statics/',
24 }
25 
26 application = tornado.web.Application([
27     (r'/index',IndexHandler)
28 ],**settings)
29 
30 if __name__ == '__main__':
31     application.listen(8888)
32     tornado.ioloop.IOLoop.instance().start()
start

注:下面全部的實例用相同的python代碼都能實現,只須要改前端代碼,python代碼文件名爲start.py

tornado生成隨機字符串

 用python生成隨機驗證碼須要借鑑一個插件,和一個io模塊,實現起來也很是容易,固然也須要借鑑session來判斷驗證碼是否錯誤,下面寫一段用戶登陸驗證帶驗證碼的,再看下效果,插件必須和執行文件必須放在更目錄下

  1 複製代碼
  2 #!/usr/bin/env python
  3 # -*- coding:utf-8 -*-
  4 import tornado.web
  5 import tornado.ioloop
  6 
  7 container = {}
  8 class Session:
  9     def __init__(self, handler):
 10         self.handler = handler
 11         self.random_str = None
 12 
 13     def __genarate_random_str(self):
 14         import hashlib
 15         import time
 16         obj = hashlib.md5()
 17         obj.update(bytes(str(time.time()), encoding='utf-8'))
 18         random_str = obj.hexdigest()
 19         return random_str
 20 
 21     def __setitem__(self, key, value):
 22         # 在container中加入隨機字符串
 23         # 定義專屬於本身的數據
 24         # 在客戶端中寫入隨機字符串
 25         # 判斷,請求的用戶是否已有隨機字符串
 26         if not self.random_str:
 27             random_str = self.handler.get_cookie('__session__')
 28             if not random_str:
 29                 random_str = self.__genarate_random_str()
 30                 container[random_str] = {}
 31             else:
 32                 # 客戶端有隨機字符串
 33                 if random_str in container.keys():
 34                     pass
 35                 else:
 36                     random_str = self.__genarate_random_str()
 37                     container[random_str] = {}
 38             self.random_str = random_str # self.random_str = asdfasdfasdfasdf
 39 
 40         container[self.random_str][key] = value
 41         self.handler.set_cookie("__session__", self.random_str)
 42 
 43     def __getitem__(self, key):
 44         # 獲取客戶端的隨機字符串
 45         # 從container中獲取專屬於個人數據
 46         #  專屬信息【key】
 47         random_str =  self.handler.get_cookie("__session__")
 48         if not random_str:
 49             return None
 50         # 客戶端有隨機字符串
 51         user_info_dict = container.get(random_str,None)
 52         if not user_info_dict:
 53             return None
 54         value = user_info_dict.get(key, None)
 55         return value
 56 
 57 
 58 class BaseHandler(tornado.web.RequestHandler):
 59     def initialize(self):
 60         self.session = Session(self)
 61 
 62 
 63 class LoginHandler(BaseHandler):
 64     def get(self, *args, **kwargs):
 65         self.render('login.html' ,state = "")
 66 
 67     def post(self, *args, **kwargs):
 68         username = self.get_argument('username')
 69         password = self.get_argument('password')
 70         code =self.get_argument('code')
 71         check_code = self.session['CheckCode']
 72         if username =="zhangyanlin" and password == "123" and code.upper() == check_code.upper():
 73             self.write("登陸成功")
 74         else:
 75             self.render('login.html',state = "驗證碼錯誤")
 76 
 77 class CheckCodeHandler(BaseHandler):
 78     def get(self, *args, **kwargs):
 79         import io
 80         import check_code
 81         mstream = io.BytesIO()
 82         img,code = check_code.create_validate_code()
 83         img.save(mstream,"GIF")
 84         self.session['CheckCode'] =code
 85         self.write(mstream.getvalue())
 86 
 87 
 88 settings = {
 89     'template_path':'views',
 90     'cookie_secret': "asdasd",
 91 }
 92 
 93 application = tornado.web.Application([
 94     (r'/login',LoginHandler),
 95     (r'/check_code',CheckCodeHandler)
 96 ],**settings)
 97 
 98 if __name__ == '__main__':
 99     application.listen(8888)
100     tornado.ioloop.IOLoop.instance().start()
start.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>驗證碼</title>
 6 </head>
 7 <body>
 8     <form action="/login" method="post">
 9         <p>用戶名: <input type="text" name="username"> </p>
10         <p>密碼: <input type="password" name="password"> </p>
11         <p>驗證碼: <input type="text" name="code"><img src="/check_code" onclick="ChangeCode();" id = "checkcode"></p>
12         <input type="submit" value="submit"> <span>{{state}}</span>
13     </form>
14 <script type="text/javascript">  //當點擊圖片的時候,會刷新圖片,這一段代碼就能夠實現
15     function ChangeCode() {
16         var code = document.getElementById('checkcode');
17         code.src += "?";
18     }
19 </script>
20 </body>
21 </html>
login.html

 插件下載地址:猛擊這裏

相關文章
相關標籤/搜索