tornado和PHP,Tornado学习笔记(一)

最近开始用Tornado做开发了,究其原因,主要是Tornado基于Python,一来代码量少开发速度快,二来采用epoll方式,能够承载的并发量很高。在我的i5台式机上用ab测试,不连接数据库的情况下,单用get生成页面,大概平均的并发量在7900左右。这比php或者java能够承载并发量都高很多很多。三来Python代码可维护性相对来说比php好很多,语法结构清晰。四来,tornado的框架设计的很黄很暴力,以HTTP请求方式作为方法名称,通常情况下,用户写一个页面只需要有get和post两种方式的方法定义就够了。

在学习的过程中遇到一些比较重要的问题,记录下来以后备查,在学习的过程中遇到不少问题,基本都是靠×××解决,百度实在是令人痛苦不堪。记录比较零散一些,可能不仅限于tornado,也会包括python的一些知识。由于我也还在学习过程中,所以有些东西不一定详尽或者理解到位,tornado高人勿拍。

tornado入门不是很难,只要理解了他处理的方式就很好做了。tornado在处理网页的时候,针对于URL的连接,实际就是对class类的一个路由映射。而类中的方法通常无非就两种,处理连接请求的get或者post。所以tornado的页面编写很简单。比如,这是一个用作验证登录用户的类,逐行解释一下:class SigninHandler(BaseHandler): #引入BaseHandler

def post(self): #HTTP的POST方法,是GET渲染的form中的post method所对应

username = self.get_argument('username') #获取form中username的值

password = self.get_argument('password') #获取form中password的值

conn = MySQLdb.connect('localhost', user = 'root', passwd = '', db = 'datacenter', charset = 'utf8', cursorclass = MySQLdb.cursors.DictCursor) #连接数据库,指定cursorclass的目的是要让返回结果以字典的形式呈现,如果不写,是以元组形式返回

cursor= conn.cursor() #定义数据库指针

sql = 'SELECT * FROM dc_users WHERE username=%s AND password=password(%s)' #写sql,为何这样写后面再说

cursor.execute(sql, (username, password,)) #执行SQL

row = cursor.fetchone() #获取一条,返回值为dict,因为前面连接数据库时定义了cursorclass = MySQLdb.cursors.DictCursor,当然,你需要import MySQLdb.cursors的包

if row: #如果存在记录

self.set_secure_cookie('id', str(row['id']).encode('unicode_escape'),  expires_days=None) #设置安全cookie,防止xsrf跨域

self.set_secure_cookie('username', row['username'].encode('unicode_escape'),  expires_days=None) #same

self.set_secure_cookie('role', row['role'].encode('unicode_escape'),  expires_days=None) #same

ip = self.request.remote_ip #获取来访者IP

sql = 'UPDATE dc_users SET last_access = NOW(), last_ip=%s WHERE id = %s' #认证审计变更的SQL

cursor.execute(sql, (ip, row['id'],)) #执行SQL

conn.commit() #提交执行

cursor.close() #关闭指针

conn.close() #关闭数据库连接

self.redirect('/') #转入首页

return #返回,按照官方文档的要求,在redirect之后需要写空的return,否则可能会有问题,实测确实会有问题

else: #如果不存在记录

self.redirect('/Signin') #跳转回登录页面

return

def get(self): #HTTP GET方式

self.render('users/login_form.html') #渲染登录框HTML

login_form.html内容如下{% include 'header.html' %} 

 

{% module xsrf_form_html() %} 

{% include 'footer.html' %}

对于主代码,应如下:#-*- coding: utf-8 -*-

import sys

reload(sys)

sys.setdefaultencoding('utf-8')

import tornado.ioloop

import tornado.web

import tornado.httpserver

import tornado.autoreload

import os

class BaseHandler(tornado.web.RequestHandler): #BaseHandler

def get_current_user(self):

user = self.get_secure_cookie('username')

return user

class IndexHandler(BaseHandler):

@tornado.web.authenticated

def get(self):

if not self.current_user:

self.redirect('/Signin') #如未登录,则跳转Signin,Signin的GET方法调用的就是login_form.html页面

return

self.render('welcome.html') #否则渲染welcome.html

settings = \

{

"cookie_secret": "HeavyMetalWillNeverDie", #Cookie secret

"xsrf_cookies": True, #开启跨域安全

"gzip": False, #关闭gzip输出

"debug": False, #关闭调试模式,其实调试模式是很纠结的一事,我喜欢打开。

"template_path": os.path.join(os.path.dirname(__file__), "./templates"), #定义模板,也就是login_form.html或header.html相对于本程序所在的位置

"static_path": os.path.join(os.path.dirname(__file__), "./static"), #定义JS, CSS等文件相对于本程序所在的位置

"login_url": "/Signin", #登录URL为/Signin

}

application = tornado.web.Application([

(r"/", IndexHandler), #路由设置/ 使用IndexHandler

(r"/signin", SigninHandler) # Signin使用SigninHandler

], **settings)

if __name__ == "__main__": #启动tornado,配置里如果打开debug,则可以使用autoload,属于development模式,如果关闭debug,则不可以使用autoload,属于production模式。autoload的含义是当tornado监测到有任何文件发生变化,不需要重启server即可看到相应的页面变化,否则是修改了东西看不到变化。

server = tornado.httpserver.HTTPServer(application)

server.bind(10002) #绑定到10002端口

server.start(0) #自动以多进程方式启动Tornado,否则需要手工启动多个进程

tornado.ioloop.IOLoop.instance().start()

对于sql部分,执行最好写成cursor.execute(sql, (id,)),将%s的东西以元组形式传递给execute方法,这样做的目的是最大程度避免SQL注入的发生。如果直接写为 'select * from xxx where id = ' + id 或者 'select * from xxx where id = %s' % id 的话,会被注入。另外,如果是sqlite3的话,需要写成 'select * from xxx where id=?' ,然后execute方式一样。

另外,如果开启了禁止xsrf跨域功能的话,在每个HTML的form表单里必须加上{% module xsrf_form_html() %}否则会出现禁止访问的错误。

下篇记录一下编码格式处理,这个在python2上最讨厌。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值