01: tornado基礎篇

目錄:Tornado其餘篇

01: tornado基礎篇javascript

02: tornado進階篇css

03: 自定義異步非阻塞tornado框架html

04: 打開tornado源碼剖析處理過程前端

目錄:

1.1 Tornado安裝與基本使用     返回頂部

  一、 安裝tornadojava

    一、pip3安裝
        pip3 install tornadopython

    二、源碼安裝
        https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gzweb

  二、tornado概述瀏覽器

      一、Tornado 是 FriendFeed 使用的可擴展的非阻塞式 web 服務器及其相關工具的開源版本服務器

      二、Tornado 和如今的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,並且速度至關快。cookie

      三、得利於其 非阻塞的方式和對 epoll 的運用,Tornado 每秒能夠處理數以千計的鏈接

      四、咱們開發這個 Web 服務器的主要目的就是爲了處理 FriendFeed 的實時功能 ——在 FriendFeed 的應用裏
           每個活動用戶都會保持着一個服務器鏈接。

  三、tornado快速上手

      一、使用pycharm建立一個普通項目s131415文件夾,並建立文件s131415/app.py
      二、在app.py中粘貼下列內容,運行app.py文件
      三、在瀏覽器中訪問: http://127.0.0.1:8888/index 便可看到「Hello, world!!」請求內容

import tornado.ioloop
import tornado.web

#一、 處理訪問/index/的get請求: http://127.0.0.1:8888/index/
class MainHandler(tornado.web.RequestHandler):
   def get(self):
      self.write("I am index!!")
      # self.redirect('http://www.baidu.com')
      # self.render('index.html',k1='v1')

#二、 處理訪問 /login/的post請求和get請求: http://127.0.0.1:8888/login/
class LoginHandler(tornado.web.RequestHandler):
   def get(self):
      self.write('login')
   def post(self,*args,**kwargs):
      self.write('login post')

#三、 配置settings
settings = {
    'template_path': 'template',         # 配置html文件模板位置
    'static_path': 'static',             # 配置靜態文件路徑(圖片等)
    'static_url_prefix': '/static/',     # 前端引入靜態文件路徑
}

#4 路由系統
application = tornado.web.Application([
   (r"/index/", MainHandler),
   (r"/login/", LoginHandler),
],**settings)

#5 啓動這個tornado這個程序
if __name__ == "__main__":
   application.listen(8888)
   tornado.ioloop.IOLoop.instance().start()
tornado基本使用

1.2 tornado各類url寫法     返回頂部

  一、無正則匹配url  (http://127.0.0.1:8000/index/?nid=1&pid=2)

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        nid = self.get_query_argument('nid')
        pid = self.get_query_argument('pid')
        self.write("Hello, world")

# http://127.0.0.1:8000/index/?nid=1&pid=2
application = tornado.web.Application([
    (r"/index/", MainHandler),
])

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

  二、基於(\d+)正則的url

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self,nid,pid):
        print(nid,pid)
        self.write("Hello, world")

# http://127.0.0.1:8000/index/1/2/
application = tornado.web.Application([
    (r"/index/(\d+)/(\d+)/", MainHandler),        # 這種只能傳數字
    # (r"/index/(\w+)/(\w+)/", MainHandler),        # 這種能夠傳數字、字母、下劃線
])

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

  三、基於正則分組(?P<nid>\d+),能夠不考慮接收參數順序 (推薦)

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self,nid,pid):
        print(nid,pid)
        self.write("Hello, world")

# http://127.0.0.1:8000/index/1/2/
application = tornado.web.Application([
    (r"/index/(?P<nid>\d+)/(?P<pid>\d+)/", MainHandler),        # 這種只能傳數字
])

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

1.3 配置settings & 獲取get,post請求     返回頂部

  一、settings可配置參數

settings = {
    'template_path': 'template',        #配置html文件模板位置
    'static_path': 'static',             #配置靜態文件路徑(圖片等)
    'static_url_prefix': '/static/',    #前端引入靜態文件路徑
    'ui_methods': mt,
    'ui_modules': md,

    'xsrf_cookies':True,
    'cookie_secret':'xxx',
    'login_url':"/auth/login",
    'autoescape':None,
    'local':"zh_CN",
    'debug':True,
}
tornado中settings字典可配置參數

  二、獲取get、post請求

import tornado.ioloop
import tornado.web

#一、 處理訪問/index/的get請求: http://127.0.0.1:9999/index
class MainHandler(tornado.web.RequestHandler):
   def get(self):
      self.write("I am index!!")
      # self.redirect('http://www.baidu.com')
      # self.render('index.html',k1='v1')

#二、 處理訪問 /login/的post請求和get請求: http://127.0.0.1:9999/login
class LoginHandler(tornado.web.RequestHandler):
   def get(self):

      #2.1 獲取url中以get方式傳遞過來的數據: http://127.0.0.1:9999/login/?username=zhangsan
      # print(self.get_query_argument('username'))        # zhangsan
      # print(self.get_query_arguments('username'))       # ['zhangsan']
      # print( self.get_argument('username') )            # get和post兩種請求傳遞的數據都能獲取

      self.render('login.html')
   def post(self,*args,**kwargs):

      #2.2 獲取請求體中以post傳遞的數據
      # print( self.get_body_argument('faver') )     # 僅能獲取單選,多選僅能獲取最後一個
      # print( self.get_body_arguments('faver') )    # ['1', '2', '3']  獲取多選

      #2.3 get和post兩種請求傳遞的數據都能獲取
      # print( self.get_argument('username') )

      #2.4 設置和獲取cookie
      # self.cookies
      # self.set_cookie()

      #2.5 設置和獲取請求頭
      # self._headers
      # self.get_header()

      self.write('login post')

#三、 配置settings
settings = {
    'template_path': 'template',         # 配置html文件模板位置
    'static_path': 'static',             # 配置靜態文件路徑(圖片等)
    'static_url_prefix': '/static/',     # 前端引入靜態文件路徑
}

#4 路由系統
application = tornado.web.Application([
   (r"/index/", MainHandler),
   (r"/login/", LoginHandler),
],**settings)

#5 啓動這個tornado這個程序
if __name__ == "__main__":
   application.listen(9999)
   tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/base.css">
</head>
<body>
    <form method="POST" action="/login/">
        <input type="text" name="username">

        <h5 class="c1">多選</h5>
            男球:<input type="checkbox" name="faver" value="1" />
            足球:<input type="checkbox" name="faver" value="2" />
            皮球:<input type="checkbox" name="faver" value="3" />
        <input type="submit" value="提交">
    </form>
</body>
</html>
/template/login.html
.c1{
    color: red;
}
/template/base.css

1.4 tornado渲染     返回頂部

  一、for循環

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
   def get(self):
      self.render("index.html", username='tom',list_info=[11, 22, 33],user_dic={'username':'zhangsan','age':77})

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

if __name__ == "__main__":
   application.listen(8888)
   tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>用戶名:{{username}}</h3>
    {% for item in list_info %}
        <li>{{item}}</li>
    {% end %}
    <p></p>
    {% for item in user_dic %}
        <li>{{item}} : {{user_dic[item]}}</li>
    {% end %}
</body>
</html>
index.html

  二、if、in、判斷相等

import tornado.ioloop
import tornado.web

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

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

if __name__ == "__main__":
   application.listen(8888)
   tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% if 11 in list_info %}
        true
    {% else %}
        false
    {% end %}
    
    {% if username == "tom" %}
        my name is {{username}}
    {% else %}
        not tom
    {% end %}
</body>
</html>
index.html

1.5 自定義UIMethod和UIModule: 相似於djando中simple_tag和自定義filter      返回頂部

  一、UIModule與UIMethod比較

      1. UIModule: 能夠傳參、能夠生成html、css、js代碼

      2. UIMethod: 這個不能傳參數,不能生成css,js等,只能生成html文件

  二、UIModule和UIMethod使用舉例

       

import tornado.ioloop
import tornado.web
from tornado.escape import linkify
import uimodules as md     #1.導入uimodules模塊
import uimethods as mt     #2.導入uimethods模塊

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'ui_methods': mt,      #3.將uimethods模塊註冊到settings中
    'ui_modules': md,      #4.將uimodules模塊註冊到settings中
}

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

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
app.py註冊
from tornado.web import UIModule
from tornado import escape

# uimodule不只能夠幫生成標籤,還能夠幫添加css,js樣式
class custom(UIModule):
   # def javascript_files(self):
   #    '''一、生成: <script src="base.js"></script> '''
   #    return ['base.js','header.js']
   #
   # def embedded_javascript(self):
   #    '''二、生成:  <script> alert(123); </script> '''
   #    return "alert(123);"
   #
   # def css_files(self):
   #    '''三、在頭部生成: <link rel="stylesheet" href="base.css">'''
   #    return ['base.css','header.css']
   #
   # def embedded_css(self):
   #    '''四、在頭部style標籤生成: <style> .c1{ color:red; } </style>'''
   #    return ".c1{color:red;}"

   def render(self, *args, **kwargs):
      '''五、生成html文件'''
      return escape.xhtml_escape('<h1>tom</h1>')
uimodules.py定義
def tab(self):
    return '<h1>tom</h1>'
uimethods.py定義
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>hello</h1>
    <p>{% module custom(123) %}</p>

    {{ tab() }}
</body>
</html>
index.html使用

1.6 模板繼承     返回頂部

   一、模板繼承使用

       1. 在master.html中定義模板:  {% block css %} {% endblock %}

       2. 在子類中引入要繼承的模板:  {% extends 'layout.html' %}

   二、模板導入

       1. 使用時直接導入便可:  {% include "header.html" %}

               

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
   def get(self):
      self.render("index.html")

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

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

if __name__ == "__main__":
   application.listen(8888)
   tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <title>{% block title %}Default title{% end %}</title>

    <link rel="stylesheet" href="/static/css/base.css">
    {% block css %}{% end %}

</head>
<body>
    <div class="c1">這裏是layout.html這個母版中的內容</div>
    {% block RenderBody %}{% end %}
</body>
</html>
layout.html 母版文件
{% extends 'layout.html'%}
{% block css %}<link rel="stylesheet" href="/static/css/index.css">{% end %}

{% block RenderBody %}
    <h3 class="c1">這個RenderBody塊繼承的是header.html這個母版</h3>

    <div>
        {% include 'header.html' %}
    </div>
{% end %}
index.html 子版中引入母版
<h3>
     這裏是header.html中的內容,須要導入的文件
</h3>
header.html 被導入的文件

1.7 tornado多文件上傳      返回頂部

import tornado.ioloop
import tornado.web

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

    def post(self, *args, **kwargs):
        file_metas = self.request.files["fff"]
        for meta in file_metas:
            file_name = meta['filename']
            with open(file_name,'wb') as up:
                print('hahah')
                up.write(meta['body'])

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

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


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>上傳文件</title>
</head>
<body>
    <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >
        <input name="fff" id="my_file"  type="file" />
        <input type="submit" value="提交"  />
    </form>
</body>
</html>
index.html

1.8 @gen.coroutine實現異步非阻塞舉例及原理解析     返回頂部

  一、tornado.gen.coroutine和tornado.web.asynchronous比較

      1. @tornado.web.asynchronous 實現長鏈接,調用self.finish()才結束
      2. @tornado.gen.coroutine 這個實現異步
      3. 你要想異步,就要保持長鏈接,不然你的handler執行完就本身return了
      4. @asynchronous會監聽@gen.coroutine的返回結果(Future),並在@gen.coroutine裝飾的代碼段執行完成後自動調用finish。
      5. 從Tornado 3.1版本開始,只使用@gen.coroutine就能夠了。

  二、tornado實現異步原理 

      1. 每一個請求過來就會建立一個socket對象,並yield一個future對象,而後tornado就處理下一個鏈接了
      2. tornado內部會以socket對象爲key,future對象爲value加入字典
      3. tornado內部調用epoll方法監聽這個全局字典,有socket對象變化就會執行future.set_result('...')
      4. 執行future.set_result('...')後就會將future.ready標誌位變成True,而後就會調用callback方法返回內容

      注1:yield 一個 Future對象,那麼Tornado會等待,直到執行future.set_result('...')纔會釋放
      注2:epoll實質是不斷的輪詢所負責的全部socket,當某個socket有數據到達了,就通知用戶進程

import tornado.ioloop
import tornado.web
from tornado import gen

class IndexHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        self.write('I am index!!')

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

if __name__ == "__main__":
    print('http://127.0.0.1:8888/index/')
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
tornado實現異步非阻塞舉例
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
from tornado import gen
from tornado.concurrent import Future


future = None
class IndexHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        global future
        future  = Future()
        future.add_done_callback(self.doing)
        yield future

    def doing(self,*args,**kwargs):
        self.write('async')
        self.finish()


class StopHandler(tornado.web.RequestHandler):
    def get(self):
        future.set_result('.......')


application = tornado.web.Application([
   (r"/index/", IndexHandler),
   (r"/stop/", StopHandler),
])

if __name__ == "__main__":
    print('http://127.0.0.1:8888/index/')
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()


'''
http://127.0.0.1:8888/index/          # 只要不返回數據,瀏覽器就不會返回一直等着保持長鏈接
http://127.0.0.1:8888/stop/           # 訪問/stop/是會調用future.set_result()此時 /index/就會返回數據
'''
使用Future對象模擬tornado異步非阻塞簡單原理
相關文章
相關標籤/搜索