1. 程式人生 > 實用技巧 >283 Tornado【第1篇】:Tornado的簡單使用以及使用

283 Tornado【第1篇】:Tornado的簡單使用以及使用

Tornado是FriendFeed使用的可擴充套件的非阻塞式 web 伺服器及其相關工具的開源版本。這個 Web 框架看起來有些像web.py或者Google 的 webapp,不過為了能有效利用非阻塞式伺服器環境,這個 Web 框架還包含了一些相關的有用工具 和優化。

Tornado 和現在的主流 Web 伺服器框架(包括大多數 Python 的框架)有著明顯的區別:它是非阻塞式伺服器,而且速度相當快。得利於其 非阻塞的方式和對epoll的運用,Tornado 每秒可以處理數以千計的連線,這意味著對於實時 Web 服務來說,Tornado 是一個理想的 Web 框架。我們開發這個 Web 伺服器的主要目的就是為了處理 FriendFeed 的實時功能 ——在 FriendFeed 的應用裡每一個活動使用者都會保持著一個伺服器連線。

pip install tornado
原始碼安裝
    https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

一、快速上手

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 ...)的不同調用並執行相應的方法

第五步:方法返回值的字串內容傳送瀏覽器

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 import tornado.ioloop 7 import tornado.web 8 from tornado import httpclient 9 from tornado.web import asynchronous 10 from tornado import gen 11 12 import uimodules as md 13 import uimethods as mt 14 15 class MainHandler(tornado.web.RequestHandler): 16 @asynchronous 17 @gen.coroutine 18 def get(self): 19 print 'start get ' 20 http = httpclient.AsyncHTTPClient() 21 http.fetch("http://127.0.0.1:8008/post/", self.callback) 22 self.write('end') 23 24 def callback(self, response): 25 print response.body 26 27 settings = { 28 'template_path': 'template', 29 'static_path': 'static', 30 'static_url_prefix': '/static/', 31 'ui_methods': mt, 32 'ui_modules': md, 33 } 34 35 application = tornado.web.Application([ 36 (r"/index", MainHandler), 37 ], **settings) 38 39 40 if __name__ == "__main__": 41 application.listen(8009) 42 tornado.ioloop.IOLoop.instance().start()
非同步非阻塞例項

二、路由系統

路由系統其實就是 url 和 類 的對應關係,這裡不同於其他框架,其他很多框架均是 url 對應 函式,Tornado中每個url對應的是一個類。

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()

三、模板

Tornao中的模板語言和django中類似,模板引擎將模板檔案載入記憶體,然後將資料嵌入其中,最終獲取到一個完整的字串,再將字串返回給請求者。

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

控制語句和對應的 Python 語句的格式基本完全相同。我們支援ifforwhiletry,這些語句邏輯結束的位置需要用{% end %}做標記。還通過extendsblock語句實現了模板繼承。這些在template模組的程式碼文件中有著詳細的描述

 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
 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
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render(
'home/index.html')

settings = {
'template_path': 'template',
}

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

if name == "main":
application.listen(
80)
tornado.ioloop.IOLoop.instance().start()

四、使用

import tornado.ioloop
import tornado.web

#檢視
class MainHandle(tornado.web.RequestHandler):
def initialize(self):
print('123') #在每一次請求開始先執行一下初始化這個方法
def get(self):
print(self.get_cookie('user'))
self.write(
'hello world') #預設有個return none
def post(self,*args,**kwargs):
pass

class LoginHandle(tornado.web.RequestHandler):
def get(self,args,**kwargs):
self.render(
'templates/login.html') #沒有脫離檔案路徑的知識
def post(self,
args,**kwargs):
user
= self.get_argument('user')
pwd
= self.get_argument('pwd')
print(user,pwd)
if user'haiyan' and pwd'123':
self.set_cookie(
'user','haiyan',10) #設定cookie,10秒後過期
self.set_secure_cookie('user','haiyan',) #簽名cookie
self.redirect('/index') #要麼return一下
else: #要麼else分割開,不然會報錯
self.render('templates/login.html')
# self.get_arguments() #getlist 像是複選框,一下取多個值

class TestHandle(tornado.web.RequestHandler):
def get(self, *args, kwargs):
sss
= {'name':"haiyan","info":{'name':'小華','age':18},"li":[11,22,33]}
self.render(
'templates/test.html',
sss)

settings={
'static_path':'static',
'xsrf_cookies':True,
'cookie_secret':'1254'
}
#路由分配
application = tornado.web.Application([
(r
'/index',MainHandle),
(r
'/login',LoginHandle),
(r
'/test',TestHandle)
],
**settings)

if name == 'main':
#建立socket物件,bind.listen
application.listen(8080)
# conn,addr = sock.accept

tornado.ioloop.IOLoop.instance().start()

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>Title</title>
</head>
<body>
<h4>登入頁面</h4>
<form action="" method="post">
{#    {{ xsrf_form_html() }}#}
    {% raw  xsrf_form_html() %}  原生的
    使用者名稱:<input type="text" name="user">
    密碼:<input type="password" name="pwd">
    <input type="submit" value="登入">
</form>
</body>
</html>

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>Title</title>
    <link rel="stylesheet" href="/static/test.css">  <!--用之前需要配置一下-->
</head>
<body>
<h1>{{ name }}</h1>
<h2>{{ info.get('age') }}</h2>
<h1>{{ info['name'] }}</h1>
<h1>{{ li }}</h1>
<h1>{{ li[0] }}</h1>

======迴圈生成=
<ul>
{% for i in li%}
<li>{{ i }}</li>
{% end %}
</ul>

</body>
</html>

五、自定義session

import tornado.ioloop
import tornado.web

#檢視
from hashlib import sha1
import os
import time
create_session_id
= lambda :sha1(bytes('%s%s'%(os.urandom(16),time.time()),encoding='')).hexdigest()
class SessionSix(object):
session_cache
= { #一開是是NOne的 #開闢一個記憶體空間,儲存這個人的狀態
# 'sddfgfhsdsffd':{},
# "sdfsdgfgd":{}
} #
def init(self,handle):
self.handle
= handle
#先獲取session_id的值
random_str = self.handle.get_cookie('_session_id')
if not random_str:
#如果沒有隨機字串,說明是第一次登陸
random_str = create_session_id()
self.session_cache[random_str]
= {}
else:
if random_str not in self.session_cache:#判斷他的session_id和自己給它的session_id是否相等
random_str = create_session_id()
self.session_cache[random_str]
= {}#你偽造了一個假的,我就認為你是第一次來
self.random_str = random_str #來表示不同的使用者對應的身份

<span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__setitem__</span><span style="color: rgba(0, 0, 0, 1)">(self, key, value):
    self.session_cache[self.random_str][key] </span>=<span style="color: rgba(0, 0, 0, 1)"> value
    self.handle.set_cookie(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">_session_id</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,create_session_id())

</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__getitem__</span><span style="color: rgba(0, 0, 0, 1)">(self, item):
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> self.session_cache[self.random_str].get(item)

</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__delitem__</span><span style="color: rgba(0, 0, 0, 1)">(self, key):
    </span><span style="color: rgba(0, 0, 255, 1)">pass</span>

class MainHandle(tornado.web.RequestHandler):
def initialize(self):
self.session
= SessionSix(self)
def get(self):
print(self.session['user']) #獲取session
# print(self.get_cookie('user'))
self.write('hello world') #預設有個return none
def post(self,*args,**kwargs):
pass

class LoginHandle(tornado.web.RequestHandler):
def initialize(self):
# print('123') #在每一次請求開始先執行一下初始化這個方法
self.session = SessionSix(self)
def get(self,args,**kwargs):
self.render(
'templates/login.html') #沒有脫離檔案路徑的知識
def post(self,
args,**kwargs):
user
= self.get_argument('user')
pwd
= self.get_argument('pwd')
print(user,pwd)
if user'haiyan' and pwd'123':
self.session[
'user'] = '666' #設定自定義的session
# self.set_cookie('user','haiyan',10) #設定cookie,10秒後過期
# self.set_secure_cookie('user','haiyan',) #簽名cookie
self.redirect('/index') #要麼return一下
else: #要麼else分割開,不然會報錯
self.render('templates/login.html')
# self.get_arguments() #getlist 像是複選框,一下取多個值

class TestHandle(tornado.web.RequestHandler):
def get(self, *args, kwargs):
sss
= {'name':"haiyan","info":{'name':'小華','age':18},"li":[11,22,33]}
self.render(
'templates/test.html',
sss)

settings={
'static_path':'static',
'xsrf_cookies':True,
'cookie_secret':'1254'
}
#路由分配
application = tornado.web.Application([
(r
'/index',MainHandle),
(r
'/login',LoginHandle),
(r
'/test',TestHandle)
],
**settings)

if name == 'main':
#建立socket物件,bind.listen
application.listen(8080)
# conn,addr = sock.accept

tornado.ioloop.IOLoop.instance().start()