
1.2 Tornado开发基础
在Python程序中使用Tornado框架之前,首先需要搭建Tornado框架环境。Tornado框架可以通过pip或者easy_install命令进行安装。pip命令如下。
pip install tornado
easy_install命令如下。
easy_install tornado
在控制台中使用easy_install命令的安装界面如图1-1所示。

图1-1 使用“easy_install”命令安装Tornado框架
1.2.1 编写第一个Tornado程序
在Tornado框架中,是通过继承类tornado.Web.RequestHandler来编写Web服务器端程序的,并编写get()、post()业务方法,以实现对客户端指定URL的GET请求和POST请求的回应。然后启动框架中提供的服务器以等待客户端连接,处理相关数据并返回请求信息。下面的实例文件app.py演示了使用Python编写一个基本Tornado程序的过程。
源码路径:daima\1\1-2\app.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 #定义子类MainHandler class MainHandler(tornado.web.RequestHandler): def get(self): #定义请求业务函数get() self.write("Hello, world") #输出文本 def make_app(): #定义应用配置函数 return tornado.web.Application([ (r"/", MainHandler), #定义URL映射列表 ]) if __name__ == "__main__": app = make_app() #调用配置函数 app.listen(8888) #设置监听服务器8888端口 tornado.ioloop.IOLoop.current().start() #启动服务器
在上述实例代码中,首先导入了Tornado框架的相关模块,然后自定义URL的响应业务方法(GET、POST等)。接下来,实例化Tornado模块中提供的Application类,并传URL映射列表及有关参数。最后启动服务器。在命令提示符下的对应子目录中执行:
python app.py
如果没有语法错误,服务器就已经启动并等待客户端连接了。在服务器运行以后,在浏览器地址栏中输入http://localhost:8888,就可以访问服务器,看到默认主页页面了。在浏览器中的执行效果如图1-2所示。

图1-2 执行效果
通过上述实例可以看出,使用Tornado框架编写的服务器端程序的结构是非常清晰的。其基本工作就是编写相关的业务处理类,并将它们和某一特定的URL映射起来,Tornado框架服务器收到对应的请求后进行调用。一般来说,对于比较简单的网站项目,可以把所有的代码放入同一个模块之中。但为了维护方便,可以按照功能将其划分到不同的模块中,其一般模块结构(目录结构)如下。
proj\ manage.py #服务器启动入口 settings.py #服务器配置文件 url.py #服务器URL配置文件 handler\ login.py #相关URL业务请求处理类 db\ #数据库操作模块目录 static\ #静态文件存放目录 js\ #JavaScript文件存放目录 css\ #CSS文件目录 img\ #图片资源文件目录 templates\ #网页模板文件目录
1.2.2 获取请求参数
在Python程序中,客户端经常需要获取如下3类参数。
•URL中的参数;
•GET的参数;
•POST中的参数。
1.获取URL中的参数
在Tornado框架中,要获取URL中包含的参数,需要在URL定义中获取参数,并在对应的业务方法中给出相应的参数名进行获取。在Tornado框架的URL定义字符串中,使用正则表达式来匹配URL及URL中的参数,比如:
(r"uid/([0-9]+)",UserHdl)
上述形式的URL字符串定义可以接受形如“uid/”后跟一位或多位数字的客户端URL请求。针对上面的URL定义,可以如下方式定义get()方法:
def get (self,uid): pass
此时,当发来匹配的URL请求时会截取与正则表达式匹配的部分,传递给get()方法,这样可以把数据传递给uid变量,以在方法get()中使用。
下面的实例文件can.py演示了在GET方法中获取URL参数的过程。
源码路径:daima\1\1-2\can.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 class zi(tornado.web.RequestHandler): #定义子类zi def get(self,uid): #获取URL参数 self.write('你好,你的UID是%s!' % uid) #显示UID,来源于下面的正则表达式 app = tornado.web.Application([ #使用正则表达式获取参数 (r'/([0-9]+)',zi), ],debug=True) if __name__ == '__main__': app.listen(8888) #设置监听服务器的8888端口 tornado.ioloop.IOLoop.instance().start() #启动服务器
在上述实例代码中,使用正则表达式定义了URL字符串,使用get()方法获取了URL参数中的UID。在浏览器中的执行效果如图1-3所示。

图1-3 执行效果
2.获取GET和POST中的参数
在Tornado框架中,要获取GET或POST中的请求参数,只需要调用从类RequestHandler中继承来的get_argument()方法即可。方法get_argument()的原型如下。
get_argument('name', default=",strip=False)
•name:请求中的参数名称。
•default:当没有获取参数时给定一个默认值。
•strip:指定是否去掉参数两侧的空格。
下面的实例文件po.py演示了获取POST参数的过程。
源码路径:daima\1\1-2\po.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 html_txt = """ #初始化变量html_txt <!DOCTYPE html> #下面是一段普通的HTML代码 <html> <body> <h2>收到GET请求</h2> <form method='post'> <input type='text' name='name' placeholder='请输入你的姓名' /> <input type='submit' value='发送POST请求' /> </form> </body> </html> """ class zi(tornado.web.RequestHandler): #定义子类zi def get(self): #定义方法get()以处理get请求 self.write(html_txt) #作为页面内容进行处理 def post(self): #定义方法post()以处理post请求 name = self.get_argument('name',default='匿名',strip=True) #获取上面表单中的姓名 self.write("你的姓名是:%s" % name) #显示姓名 app = tornado.web.Application([ #实例化Application对象 (r'/get',zi), ],debug=True) if __name__ == '__main__': app.listen(8888) #设置监听服务器的8888端口 tornado.ioloop.IOLoop.instance().start() #启动服务器
在上述实例代码中,当服务器收到GET请求时返回一个带有表单的页面内容;当用户填写自己的姓名并单击“发送POST请求”按钮时,将用户输入的姓名以POST参数形式发送到服务器端。最后在服务器端调用方法get_argument()来获取输出请求。在浏览器中输入“http://localhost:8888/get”后的初始执行效果如图1-4所示。

图1-4 初始执行效果
在表单中输入姓名“浪潮软件”,然后单击“发送POST请求”按钮后的执行效果如图1-5所示。

图1-5 输入信息并单击按钮后的执行效果
1.2.3 使用cookie
cookie(有时也用其复数形式cookies)指某些网站为了辨别用户身份、进行会话跟踪而存储在用户本地终端上的数据(通常经过加密)。在现实应用中,服务器可以利用cookie包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。cookie最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是cookie的功用。另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入cookie,以便在最后付款时提取信息。
在Tornado框架中提供了直接作用于一般cookie和安全cookie的方法。安全的cookie指存储在客户端的cookie是经过加密的,客户端只能查看到加密后的数据。在Tornado框架中,使用cookie和安全cookie的常用方法原型如下。
•set_cookie('name',value):设置cookie。
•get_cookie('name'):获取cookie值。
•set_secure_cookie ('name',value):设置安全cookie值。
•get_secure_cookie('name'):获取安全cookie值。
•clear_cookie('name'):清除名为name的cookie值。
•clear_all_cookies():清除所有cookie。
下面的实例文件co.py演示了在不同页面中设置与获取cookie值的过程。
源码路径:daima\1\1-2\co.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 import tornado.escape #导入Tornado框架中的相关模块 #定义处理类aaaa,用于设置cookie的值 class aaaa(tornado.web.RequestHandler): def get(self): #处理get请求 #URL编码处理 self.set_cookie('odn_cookie',tornado.escape.url_escape("未加密COOKIE串")) #设置普通cookie self.set_secure_cookie('scr_cookie',"加密SCURE_COOKIE串") #设置加密cookie self.write("<a href='/shcook'>查看设置的COOKIE</a>") #定义处理类shcookHdl,用于获取cookie的值 class shcookHdl(tornado.web.RequestHandler): def get(self): #处理get请求 #获取普通cookie odn_cookie = tornado.escape.url_unescape(self.get_cookie('odn_cookie')) #进行URL解码 scr_cookie = self.get_secure_cookie('scr_cookie').decode('utf-8') #获取加密cookie self.write("普通COOKIE:%s,<br />安全COOKIE:%s" % (odn_cookie,scr_cookie)) app = tornado.web.Application([ (r'/sscook',aaaa), (r'/shcook',shcookHdl), ],cookie_secret='abcddddkdk##$$34323sdDsdfdsf#23') if __name__ == '__main__': app.listen(8888) #设置监听服务器的8888端口 tornado.ioloop.IOLoop.instance().start() #启动服务器
在上述实例代码中定义了两个类,分别用于设置cookie的值和获取cookie的值。当在浏览器中输入“http://localhost:8888/sscook”时开始设置cookie,初始执行效果如图1-6所示。

图1-6 初始执行效果
当单击页面中的“查看设置的COOKIE”链接时,会访问“shcook”,显示出刚刚设置的cookie值。执行效果如图1-7所示。

图1-7 单击“查看设置的COOKIE”链接后的执行效果
1.2.4 URL转向
所谓URL转向,是通过服务器的特殊设置,将访问当前域名的用户引导到用户指定的另一个URL页面。在Tornado框架中可以实现URL转向的功能,这需要借助如下两个方法实现URL转向功能。
•redirect(url):在业务逻辑中转向URL。
•RedirectHandler:实现某个URL的直接转向。
使用类RedirectHandler的语法格式如下。
(r'/aaa', tornado.Web.RedirectHandler, dict (url='/abc'))
下面的实例文件zh.py演示了实现两种URL转向功能的过程。
源码路径:daima\1\1-2\zh.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 #定义类DistA,作为转向的目标URL请求处理程序 class DistA(tornado.web.RequestHandler): def get(self): #获取get请求 self.write("被转向的目标页面!") #显示一个字符串 #定义转向处理器类SrcA class SrcA(tornado.web.RequestHandler): def get(self): #获取get请求 self.redirect('/dist') #业务逻辑转向,指向一个URL app = tornado.web.Application([ (r'/dist',DistA), #指向DistA类 (r'/src',SrcA), #指向SrcA类 (r'/rdrt',tornado.web.RedirectHandler,{'url':'/src'}) #定义一个直接转向URL ]) if __name__ == '__main__': app.listen(8888) #设置监听服务器的8888端口 tornado.ioloop.IOLoop.instance().start() #启动服务器
在上述实例代码中定义了两个类,其中类DistA作为转向的目标URL请求处理程序,类SrcA是转向处理程序。当访问指向这个业务类时,会转向“/dist”网址。最后,在类Application中定义一个直接转向,只要访问“/rdrt”就会直接转向“/src”。在执行后如果试图访问“/rdrt”的URL,会转向“/src”,再最终转向“/dist”。也就是说,无论是访问“/rdrt”,还是访问“/src”,最终的执行效果都如图1-8所示。

图1-8 执行效果
1.2.5 使用静态资源文件
大多数Web应用程序都有一组对所有用户一视同仁的文件,这些文件在应用程序运行时是不会发生变化的。这些可以是用于网站装饰的媒体文件(如图片),用于描述如何在屏幕上绘制网页的CSS,能够被浏览器下载和执行的JavaScript代码,不含动态内容的HTML页面等。这些不发生变化的文件称为静态资源文件。
Tornado框架支持在网站页面中直接使用静态的资源文件,如图片、JavaScript脚本、CSS等。当需要用到静态文件资源时,需要在Application类初始化时提供“static_path”参数。下面的实例文件tu.py演示了使用图片静态资源文件的过程。
源码路径:daima\1\1-2\tu.py
import tornado.ioloop #导入Tornado框架中的相关模块 import tornado.web #导入Tornado框架中的相关模块 #定义类AAA,用于访问输出静态图片文件 class AAA(tornado.web.RequestHandler): def get(self): #获取get请求 self.write("<img src='/static/ttt.jpg' />") #使用一幅本地图片 app = tornado.web.Application([ (r'/stt',AAA), #参数"/stt"的请求 ],static_path='./static') #调用本网站中的图片"static/ttt.jpg" if __name__ == '__main__': app.listen(8888) #设置监听的服务器8888端口 tornado.ioloop.IOLoop.instance().start() #启动服务器
在上述实例代码中,通过参数“/stt”请求返回HTML代码中的一个img标签,并调用本网站中的图片“static/ttt.jpg”。在初始化类Application时提供了static_path参数,以指明静态资源的目录。最终的执行效果如图1-9所示。

图1-9 执行效果