首页 > 代码库 > 1Python全栈之路系列之Tornado Web框架

1Python全栈之路系列之Tornado Web框架

Python全栈之路系列之Tornado Web框架


Tornado是一个Python web框架和异步网络库,起初由FriendFeed开发. 通过使用非阻塞网络I/O,Tornado可以支撑上万级的连接,处理长连接, WebSockets,和其他需要与每个用户保持长久连接的应用.


Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。

通过pip3快速自动安装tornado

pip3 install tornado

手动源码安装

tar xvzf tornado-x.x.tar.gz
cd tornado-x.x
python setup.py build
sudo python setup.py install

启动一个简单的tornado WebServer

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

# 导入启动一个tornado所需要的模块
import tornado.ioloop
import tornado.web

# 创建一个类,继承tornado.web.RequestHandler类
class MainHandler(tornado.web.RequestHandler):
    # 如果提交的方式是get方式,那么就执行get类
    def get(self):
        # write=返回字符串
        self.write("Hello, world")
        
# 路由映射系统,如果访问的路径没有在这个路由系统中,那么就报404
application = tornado.web.Application([
    # 视图,访问"/"的时候交给"MainHandler"类处理
    (r‘/‘, MainHandler),
])

if __name__ == "__main__":
    # 监听"8888"端口
    application.listen(8888)
    # 运行socket
    tornado.ioloop.IOLoop.instance().start()

通过Linux下的curl命令访问127.0.0.1:8888

ansheng@Darker:~$ curl 127.0.0.1:8888
Hello, world
ansheng@Darker:~$

模板路径的配置

选项描述调用示例
"tempalte_path": "template",HTML模板文件self.render("template/index.html")
"static_path": "static",静态文件的配置<img src="http://www.mamicode.com/static/logo.jpg">
"static_url_prefix": "/img/",静态文件的前缀<img src="http://www.mamicode.com/img/logo.jpg">

一个示例叫你如何使用模板路径配置

python代码

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

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # render=返回一个html,查找的html文件路径默认是当前路径
        self.render("template/index.html")
        # self.redirect(‘/URL‘)  # 页面跳转
        
settings = {
    "tempalte_path": "template",  # 模板文件
    "static_path": "static",  # 静态文件的配置
    "static_url_prefix": "/img/",  # 静态文件的前缀
}

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

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

html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1 style="color: rebeccapurple">Hello World!</h1>

<img src="http://www.mamicode.com/img/logo.jpg">

</body>
</html>

curl一下

ansheng@Darker:~$ curl 127.0.0.1:8888
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color: rebeccapurple">Hello World!</h1>
<img src="http://www.mamicode.com/img/logo.jpg">
</body>
</html>
ansheng@Darker:~$

查看一下图片

ansheng@Darker:~$ curl -I 127.0.0.1:8888/img/logo.jpg
HTTP/1.1 200 OK
Server: TornadoServer/4.4
Etag: "cc1df4316e5f10c2aeddda15a5cad9e2"
Accept-Ranges: bytes
Last-Modified: Thu, 07 Jul 2016 01:46:10 GMT
Content-Type: image/jpeg
Date: Thu, 28 Jul 2016 14:45:14 GMT
Content-Length: 76459

根据用户的输入,动态的添加内容

python代码

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

import tornado.ioloop
import tornado.web

# 全局变量INPUT_LIST,用户接收用户提交过来的值
INPUT_LIST = []

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # self.get_argument(‘val‘) 获取用户提交的数据
        val = self.get_argument(‘val‘, None)
        if val:
            # 如果获取道了数据,那么就把获取到的数据添加到全局变量INPUT_LIST中
            INPUT_LIST.append(val)
        self.render("template/index.html", input_list=INPUT_LIST)
        
# 1.打开"index.html"文件,读取内容(包含特殊语法)
# 2.传过来的值与特殊的语法进行一个渲染
# 3.得到已经渲染之后的字符串
# 4.返回给用户渲染之后的字符串

settings = {
    "tempalte_path": "template",  # 模板文件
}

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

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

html代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!-- 提交方式为get,提交到/ -->
<form method="post" action="/">
    <input type="text" name="val" />
    <input type="submit" />
</form>

<ul>
    {% for item in input_list %}
    <li>{{ item }}</li>
    {% end %}
</ul>

</body>
</html>

技术分享

自定义模板语言UIMethod和UIModule

模板语言分为三大类

代码块

{% for item in input_list %}
<li>{{ item }}</li>
{% end %}

{{ item }}
一个表达式或者一个值,例如返回的时候传入一个参数NPM:

self.render("template/index2.html", npm="NPM")

前端页面接收

<p>{{ npm }}</p>

函数处理模板(uimethods和uimodules)

# uimethods.py
def mtFunc(self, arg):
    return ‘uimethods‘
    
# uimodules.py
from tornado.web import UIModule

class mdClass(UIModule):
    def render(self, *args, **kwargs):
        return ‘uimodules‘

注册

import uimethods as mt
import uimodules as md
# 先导入上面两个模块,然后再settings字段加入以下内容
settings = {
    ........,
    ‘ui_methods‘: mt,
    ‘ui_modules‘: md,
}

使用

<!-- ui_modules调用方式 -->
{% module mdClass() %}
<!-- ui_methods调用方式 -->
{{ mtFunc(val) }}

返回结果

技术分享

默认的函数、字段、类

方法描述
escapetornado.escape.xhtml_escape的別名
xhtml_escapetornado.escape.xhtml_escape的別名
url_escapetornado.escape.url_escape的別名
json_encodetornado.escape.json_encode的別名
squeezetornado.escape.squeeze的別名
datetimePython的datetime模组
handler当前的 RequestHandler对象
requesthandler.request的別名
current_userhandler.current_user的別名
localehandler.locale的別名
static_urlhandler.static_url的別名,对静态文件做缓存
xsrf_form_htmlhandler.xsrf_form_html的別名

路由

基于正则的路由

class MainHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        print(args)
        self.write("Hello Wrold")
        
application = tornado.web.Application([
    # 在路由中可以写入正则表达式
    (r‘/(\d*)/(\w*)‘, MainHandler),
    (r‘/(?P<number>\d*)/(?P<nid>\w*)‘, MainHandler),
])

二级域名的路由

二级域名这个功能实在Tornado中特有的,实现的代码为:

class WwwHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("
         
class MyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("my.ansheng.me")
        
application = tornado.web.Application([
    (r‘/‘, WwwHandler),
])

application.add_handlers(‘my.ansheng.me$‘, [
    (r‘/‘, MyHandler)
])

本机的hosts文件内加入以下内容:

127.0.0.1 www.ansheng.me
127.0.0.1 my.ansheng.me

效果图

技术分享

模板的继承与导入

继承

<!-- layout.html -->
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link href="http://www.mamicode.com/{{static_url("css/common.css")}}" rel="stylesheet" />
    {% block CSS %}{% end %}
</head>
<body>
    <div class="pg-header">
    
    </div>
    {% block RenderBody %}{% end %}
    <script src="http://www.mamicode.com/{{static_url("js/jquery-1.8.2.min.js")}}"></script>
    {% block JavaScript %}{% end %}
</body>
</html>

<!-- index.html -->
{% extends ‘layout.html‘%}
{% block CSS %}
    <link href="http://www.mamicode.com/{{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 %}

导入

<!-- header.html -->
<div>
    <ul>
        <li>1024</li>
        <li>42区</li>
    </ul>
</div>
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <link href="http://www.mamicode.com/{{static_url("css/common.css")}}" rel="stylesheet" />
</head>
<body>
    <div class="pg-header">
        {% include ‘header.html‘ %}
    </div>
    <script src="http://www.mamicode.com/{{static_url("js/jquery-1.8.2.min.js")}}"></script>
</body>
</html>

#Python全栈之路 #Tornado


1Python全栈之路系列之Tornado Web框架