文章目录

  • 1. 前言
  • 2. 从 hello, world 开始
  • 3. 最简单的登录
  • 4. 模板技术
  • 5. Cookie 演练
  • 6. Session 扩展
  • 7. 后记

1. 前言

一身转战三千里,一剑曾当百万师。
今日赠君tornado,长风破浪会有时。

python 旗下,群英荟萃,豪杰并起。单是用于 web 开发的,就有 webpy、web2py、bottle、pyramid、zope2、flask、tornado、django 等等,不一而足。最近几年较为流行的,大概也就是flask、tornado 和 django 了。

关于以上各个 web 开发框架的性能比较,上网一搜,铺天盖地——这不是本文讨论的重点,但有一点我想提醒大家:在以上众多模块中,只有 tornado 同时具备异步IO、webserver、web框架三大功能,同时又是最简洁的、学习门槛最低的。有 python 语言基础的程序员,只需要花十分钟就可以登堂入室了。

对于 tornado,我有很深的情感。如果把 web 开发框架比作程序员手中的冷兵器,我觉得 flask 好比是花枪, 轻灵飘逸,舞之令人眼花缭乱;django 像大戟,合矛戈为一体,可直刺,可横击,威力无比;tornado 秀外而惠中,更像是剑。剑在中国传统武术中有着很高的地位,为兵器之神,被认为有君子之风。

2. 从 hello, world 开始

言归正传。如果你的 python 环境还没有安装 tornado,请直接使用 pip 安装:

pip install tornado

下面的代码,虽然只有区区六行(不包括导入模块的两行),却是一个完整的 web 服务程序。运行下面的代码,就开启了一个 web 服务,从本机浏览器直接访问 http://127.0.0.1,不出意外的话,我们的第一个网页 hello, world 即可正常显示出来。

demo.py

# -*- coding: utf-8 -*-import tornado.ioloop
import tornado.webclass HomeHandler(tornado.web.RequestHandler): def get(self): # 响应以get方式发送的请求self.write("hello, world") # 向请求者(浏览器)应答hello, worldapp = tornado.web.Application([ (r"/", HomeHandler), ]) # URL映射
app.listen(80) # 绑定侦听端口
tornado.ioloop.IOLoop.instance().start() # 启动服务

如果多少了解一点 http 协议,知道 get / post 方法,相信你一定能够读懂。也许你的项目规划了很多的url,也许你的服务需要监听非80端口,没有关系,在这个代码上扩展就行。仅仅六行!!!请让我们向犀利的、简洁的、无所不能的 python 致敬!

划重点:tornado.web.RequestHandler.write() 不只可以接受字符串参数,还可以接受列表或字典参数——如果应答类型为json时,这个重载特性非常高效

3. 最简单的登录

假定我们有这样一个 web 服务需求:

  1. 首页:地址“/”,显示“点此登录”两个汉字,点击则跳转到登录页面
  2. 登录页:地址“/login”,以 get 方式访问,则显示账号、密码输入框和登录按钮;以 post 方式访问,则是提交表单提交,验证登录信息。登录成功,跳转至个人信息页面,否则,跳转至首页
  3. 个人信息页:地址“/me”,显示登录账号

以上面的代码为基础,我们首先要做的工作是 URL 和 对应的处理类之间的关联。这件工作实际上是非常轻松愉快的:

app = tornado.web.Application([(r"/", HomeHandler), (r"/login", LoginHandler), (r"/me", MeHandler)
])

接下来,我们要实现 HomeHandler、LoginHandler 和 MeHandler 这三个类了。通常,我们习惯把这些和URL 对应的处理类,保存为一个独立的文件,比如文件名为 handlers.py,然后在服务器脚本 demo.py 中导入它们。

handlers.py

# -*- coding: utf-8 -*-import tornado.webclass HomeHandler(tornado.web.RequestHandler): """响应主页请求"""def get(self): # 以get方式请求self.write("""<!DOCTYPE html><html><body><a href="login">点此登录</a></body></html>""")class LoginHandler(tornado.web.RequestHandler): """响应登录页请求"""def get(self): # 以get方式请求self.write("""<!DOCTYPE html><html><body><form method="POST" action="/login">账号:<input type="text" name="account" value="" /><br />密码:<input type="password" name="passwd" value="" /><input type="submit" value="确定" /></form></body></html>""")def post(self): # 以post方式请求(本例为提交表单)account = self.get_argument('account', None)passwd = self.get_argument('passwd', None)if account == 'xufive' and passwd == 'dgdgwstd':self.redirect('/me?name=%s'%account)else:self.redirect('/')class MeHandler(tornado.web.RequestHandler): """响应个人信息页请求"""def get(self): # 以get方式请求name = self.get_argument('name', None)if name:self.write("""<!DOCTYPE html><html><head><meta charset="UTF-8" /></head><body>欢迎你来到这里,%s</body></html>"""%name)else:self.redirect('/')

相应地,服务脚本变成了这样:

demo.py

# -*- coding: utf-8 -*-import os
import tornado.ioloop
import tornado.web
from tornado.options import parse_command_linefrom handlers import *parse_command_line()
app = tornado.web.Application(handlers=[(r"/", HomeHandler), (r"/login", LoginHandler), (r"/me", MeHandler)],template_path = os.path.join(os.path.dirname(__file__), 'templates')
)
app.listen(80) # 绑定侦听端口
tornado.ioloop.IOLoop.instance().start() # 启动服务

划重点:tornado.web.RequestHandler.get_argument() 可以读取通过表单和QueryString传递的参数

4. 模板技术

读到这里,你一定会觉得奇怪:为什么服务端程序里面混杂了一大堆的 html 代码?Don’t worry,以上的代码仅仅是帮助你建立基本概念的,实际上,tornado 是为数不多的支持模板技术很到位的框架之一,其模板技术不仅支持继承,支持子模版。让我们一步一步讨论如何使用模板。

第1步:模板保存在哪儿?

在服务端脚本里,当我们使用 tornado.web.Application() 创建一个应用时,通常需要传递一个 template_path 参数,这个参数就是模板文件的保存路径。上面的例子已经增加了这个参数,我们只要把模板文件放在和 demo.py 同级的 templates 文件夹下就可以了。

第2步:怎样写模板?

其实,模板就是 html 文件,只是其中混杂了少量特别约定的符号。一个 web 项目,通常由若干页面组成,这些页面有很多共同的地方,因此一个基类模板是必要的。

base.html

<!DOCTYPE html>
<html><head><meta charset="utf-8"><!-- 此处省略各种样式表文件 --></head><body>{% block block_body %}{% end %}</body>
<html>

基类模板 base.html 定义了一个 block_body 容器,如果有必要,我们在基类模板的任意位置定义更多的容器。假定我们需要一个个人信息页模板,可以直接继承 base.html,然后只填写 block_body 这一部分就行了。

me.html

{% extends "base.html" %}
{% block block_body %}
<h1>欢迎你来到这里,{{name}}</h1>
{% end %}

个人信息页模板引中,我们使用 {{}} 引用了一个变量 name

第3步:如何使用模板?

很简单,前面我们用 tornado.web.RequestHandler.write() 向浏览器应答信息,现在则是这样使用模板:

class MeHandler(tornado.web.RequestHandler): """响应个人信息页请求"""def get(self): # 以get方式请求name = self.get_argument('name', None)if name:self.render('me.html', name=name )else:self.redirect('/')

常用的模板语法汇总如下

  1. 引用变量:{{…}}
  2. 引用 python 表达式:{%…%}
  3. 循环:{% for var in expr %}…{% end %}
  4. 分支:{% if condition %}…{% elif condition %}…{% else %}…{% end %}
  5. 引用原生表达式:{% raw expr %}

5. Cookie 演练

tornado.web.RequestHandler 的 cookie 操作非常灵活,下面的 handler 展示了 cookie 的基本读写方法:

class CookieHandler(tornado.web.RequestHandler): def get(self): visit_num = self.get_cookie('visit_num')if not visit_num:visit_num = '0'visit_num = str(int(visit_num)+1)#self.set_cookie('visit_num', visit_num, expires=None) # 内存cookieself.set_cookie('visit_num', visit_num, expires=time.time()+1000) # 持久化的cookieself.write("这是您第%s次访问本页面"%visit_num)

如果我们要使用持久化的 Cookie(硬盘 Cookie),为了防止被破解,一般是要加密的,那么,在 tornado.web.Application 中需要设置 cookie_secret 项(加密因子)。

定义tornado.web.Application,这是我最常用的一个模式:

class Application(tornado.web.Application):def __init__(self):handlers = [(r"/", WelcomeHandler),                # 欢迎信息(r"/server_time",ServerTimeHandler)    # 显示服务器时间]settings = dict(title = u"网站名称",template_path = os.path.join(os.path.dirname(__file__), 'templates'),static_path = os.path.join(os.path.dirname(__file__), 'static'),cookie_secret = 'rewqr4gfd654fdsg@$%34dfs',session_expiry = 0,login_url = "/",debug = 1)tornado.web.Application.__init__(self, handlers, **settings)

6. Session 扩展

为 tornado 增加 session 机制,基本思路就是从 tornado.web.RequestHandler 派生新类,重写 initialize() 方法。当类实例被构造函数创建后,会先运行该方法。我们定义 initialize() 方法读取名为 session_id 的 cookie,如果存在,则读取以 session_id 命名的 session 文件,取得 session 内容,否则,session 为空。详情参见拙作《给 tornado 加装 session 轮子》,这里不再赘述。

7. 后记

本文仅仅肤浅地介绍了如何走进 tornado 的世界,资料源于我讲课的 ppt 和项目实战。因为成文仓促,没有考虑版本兼容性,难免有错误或疏漏,请多海涵。作为流行框架,tornado 还支持Asynchronous Client 以及 web Socket 等几乎所有的 web 技术,要想精通它,需要好好阅读它的 document。

十分钟学会 web 开发利器 tornado相关推荐

  1. 虚拟局域网软件开源_玩转虚拟机,十分钟学会一台电脑安装3个操作系统

    玩转虚拟机,十分钟学会一台电脑安装3个操作系统 本文目录 一.什么是虚拟机 1.普通虚拟机 2.Java虚拟机 二.虚拟机的作用 三.虚拟机的安装需求 四.常用的虚拟机软件 1.VMware虚拟机 2 ...

  2. 十分钟教你开发EOS智能合约

    十分钟教你开发EOS智能合约 在CSDN.柏链道捷(PDJ Education).HelloEOS.中关村区块链产业联盟主办的「EOS入门及最新技术解读」专场沙龙上,柏链道捷(PDJ Educatio ...

  3. 一些生活中简单可用的技能--十分钟学会,终生受益

    一些日常生活中简单可用的技能 十分钟学会,终生受益 工作 学习 生活 社交 十分钟学会,终生受益 下面的文章是从知乎高赞回答中"日常生活中有哪些十分钟就能学会并可以终生受用的技能?" ...

  4. 十分钟学会win10系统封装之系列教程(一):在VMware Workstation虚拟机上安装win10母盘系统

    关于系统封装这个话题,历来就一直受到很多小伙伴的青睐,很多同学都认为会封装系统是一件很高大上的事情,所以一直都有很多小伙伴向亦是美网络小编询问到底什么时候能出一些关于win10系统封装的教程,其实小编 ...

  5. 十大移动web开发工具

    以下列出的这些是目前十大移动web开发工具,移动开发者可以(根据具体情况)用这些工具来创建apps,实现丰富的功能.欢迎提出宝贵意见. 1)mobl-lang Mobl是一款免费且开源的语言,可以加快 ...

  6. java中xml的组装与解析(十分钟学会)

    xml的组装与解析(十分钟学会) 一.xml的解析 话不多说直接上代码 1.引入pom依赖 // 解析xml <dependency><groupId>org.jsoup< ...

  7. 十分钟学会用Go编写Web中间件

    中间件(通常)是一小段代码,它们接收一个请求,对其进行处理,每个中间件只处理一件事情,完成后将其传递给另一个中间件或最终处理程序,这样就做到了程序的解耦.如果没有中间件那么我们必须在最终的处理程序中来 ...

  8. Python + wordcloud + jieba 十分钟学会生成中文词云

    前述 本文需要的两个Python类库 jieba:中文分词分词工具 wordcloud:Python下的词云生成工具 写作本篇文章用时一个小时半,阅读需要十分钟,读完该文章后你将学会如何将任意中文文本 ...

  9. Python + wordcloud + jieba 十分钟学会用任意中文文本生成词云

    前述 本文需要的两个Python类库  jieba:中文分词分词工具  wordcloud:Python下的词云生成工具 写作本篇文章用时一个小时半,阅读需要十分钟,读完该文章后你将学会如何将任意中文 ...

最新文章

  1. 使用 AFNetworking 进行 XML 和 JSON 数据请求
  2. 程序员过年最怕问到什么?
  3. Fortify:五大SOA架构都有安全漏洞
  4. [记录]使用openGL显示点云的一个程序
  5. spring:《spring实战》读后感三
  6. 浏览器的渲染原理简介
  7. air flow空调上是什么意思_空调跳闸显cF什么意思
  8. oracle一个表拆成多个表,oracle – 在oracle表中将多个以逗号分隔的值拆分为多行...
  9. Java面向对象(5)--类的成员构造器(构造方法)
  10. cannot use a string pattern on a bytes-like object(bytes与str互转)
  11. 心率 心律 脉率的区别
  12. 华为服务器备件系统,华为企业业务中国区经销商备件系列宣传(共8期)
  13. 区块链“国家队”上新,天津重磅发布自主可控区块链系统“海河智链”
  14. 科学计数法 (C语言)
  15. 两个转子的转轮机原理详解与算法实现
  16. 20155313 杨瀚 《网络对抗技术》实验五 MSF基础应用
  17. 北京大学网络教育学院计算机,北京大学继续教育部
  18. mysql分析问卷_问卷调查相关表
  19. 播布客LINUX视频笔记
  20. Java为PDF文档加密

热门文章

  1. 两种快速打造App的方法
  2. Zfile-轻量开源个人网盘【超简单部署】
  3. 【Java.bug】(1)Can‘t find bundle for base name xxx, locale zh_CN
  4. 华为工业互联网白皮书
  5. ChatGPT为什么可以取代那么多职位?
  6. 宣传部第二学期第一次培训
  7. centos mount ntfs文件系统
  8. 系统屏幕键盘(软键盘)打开和关闭
  9. twine创建软链接_如何使用Twine和SugarCube创建交互式冒险游戏
  10. 父类和子类方法的调用