python边写边学习——简单的svn同步(二)
上个类里边貌似就回顾了两个知识点,赶脚有点慢额。接着来,这篇以tornado的框架为主。
首先介绍下。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题。
安装起来也比较简便,pip install tornado即可。
主要模块
web - FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能
escape - XHTML, JSON, URL 的编码/解码方法
database - 对 MySQLdb 的简单封装,使其更容易使用(高版本tornado3.0已移除这个类,仅一些简单的封装)
template - 基于 Python 的 web 模板系统(一些前端样式模板,没有深入使用过,但根据文档来看不太丰富)
httpclient - 非阻塞式 HTTP 客户端,它被设计用来和 web 及 httpserver 协同工作
auth - 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)
locale - 针对本地化和翻译的支持
options - 命令行和配置文件解析工具,针对服务器环境做了优化
- 1.处理请求
以官方文档为例。Tornado 的 Web 程序会将 URL 或者 URL 范式映射到 tornado.web.RequestHandler 的子类上去。在其子类中定义了 get() 或 post() 方法,用以处理不同的 HTTP 请求。
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("You requested the main page")
class StoryHandler(tornado.web.RequestHandler):
def get(self, story_id):
self.write("You requested the story " + story_id)
#'/'代表根路径。即'/'和'/stroy'将会映射到第二个参数处理器中,在处理器中又有为get方法、post方法的处理。若在处理中未写针对方法,如上述StoryHandler若使用get方法访问时将会报错。
#后面可添加N个参数使用get方法直接拿到,显然不介意这样做
application = tornado.web.Application([
(r"/", MainHandler),
(r"/story/([0-9]+)", StoryHandler),
])
如可以这样写:
class TestHandler(tornado.web.RequestHandler):
def get(self,name1,name2,name3):
self.write(name1)
self.write(name2)
self.write(name3)
application = tornado.web.Application([
(r"/svn", UpdateHandler),
(r"/test/([a-z]*)/([a-z]*)/([a-z]*)",TestHandler)
])
以上写法参数传入参数必须填满,不可缺少位置也不可换。对于正常的网站来说应该会很少使用这种方式来获取参数的。
那么获取参数申明方法为:
#第一个参数为获取参数名称
#第二参数为默认值
#第三参数默认去除两端空格
get_argument(self, name, default=_ARG_DEFAULT, strip=True)
get_arguments(self, name, strip=True)
-2.接受控制器内方法重写
RequestHandler 的方法函数重写
除了 get()/post()等以外,RequestHandler 中的一些别的方法函数,这都是 一些空函数,它们存在的目的是在必要时在子类中重新定义其内容。
get_error_html(self, status_code, exception=None, **kwargs) - 以字符串的形式 返回 HTML,以供错误页面使用。
get_current_user(self) - 用户认证
get_user_locale(self) - 返回 locale 对象,以供当前用户使用。
get_login_url(self) - 返回登录网址,以供 @authenticated 装饰器使用(默认位置 在 Application 设置中)
get_template_path(self) - 返回模板文件的路径(默认是 Application 中的设置)
initialize(self) - 初始化时候调用,同__init__方法
-3.重定向操作
重定向有两种实现方式,一种继承RedirectHandle,一种直接调用self.redirect()方法。讲真我觉着直接调用方法就好了,除非需要使用301跳转,301跳转的方法可以直接增加参数:
self.redirect('/page', permanent=True)
注意,在 self.redirect 和 RedirectHandler 中,permanent 的默认值是不同的。 这样做是有一定道理的,self.redirect 通常会被用在自定义方法中,由逻辑事件触发的。而 RedirectHandler 是在每次匹配到请求 URL 时被触发。
-4.视图模板
略。楼主没有深究,以接口为主而不是作为可视化模板.
-5.Cookie 和安全 Cookie
set_cookie和set_secure_cookie,前者直接设置浏览器cookie,后者会需要配置一个加密码进行加密并验证。官方示例在此:
application = tornado.web.Application([
(r"/", MainHandler),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
实现方式为时间戳加上Hash加密,判断时间戳是否过期以及判断hash是否正确。
暂时用到的东西基本上就以上,其它先保留一个链接,需要时候再验证和测试:http://www.tornadoweb.cn/documentation#requesthandler
下面是tornado的监听文件代码:
# -*- coding: utf-8 -*-
from tornado import ioloop
import tornado.web
import dal.mysqldb
import subversionService
import dal.mysqlConfig
import dal.dbOperation
import os
class UpdateHandler(tornado.web.RequestHandler):
def get(self):
'''获取数据库中当前版本信息'''
mysqlConnect = dal.mysqldb.mysqlConnect()
cursorInstance = mysqlConnect.get_cursor_instance()
taskId = self.get_argument('taskId','0')
host = self.get_argument('host','')
try:
taskId = int(taskId)
except Exception, e:
print 'task error'
exit(1)
try:
host = str(host)
except Exception, e:
print 'host error'
exit(1)
sql = "select * from task WHERE id = %d limit 1"%(taskId)
cursorInstance.execute(sql)
result = cursorInstance.fetchone()
dbVersion = result[2]
'''获取当前工作目录中的版本信息'''
versionService = subversionService.versionService()
versionBefore = versionService.get_version()
if int(versionBefore) < int(dbVersion):
command = 'cd ' + dal.mysqlConfig.projectPath + ' && svn up'
commandResult = os.system(command)
if not commandResult:
dal.dbOperation.insertRecord(taskId, host, 'error update', 0)
exit(1)
versionAfter = versionService.get_version()
if int(dbVersion) == int(versionAfter):
'''直接记录到数据库中'''
dal.dbOperation.insertRecord(taskId,host,'success update',1)
else:
dal.dbOperation.insertRecord(taskId, host, 'error update', 0)
else:
dal.dbOperation.insertRecord(taskId, host, 'already updated', 0)
self.write('versionBefore:' + versionBefore + 'dbVersion:'+dbVersion)
application = tornado.web.Application([
(r"/svn", UpdateHandler),
])
if __name__ == "__main__":
application.listen(8878)
tornado.ioloop.IOLoop.instance().start()