一、建立一个简单的 hello world 网页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import tornado.ioloop
import tornado.web
 
class MainHandler( tornado.web.RequestHandler ):
    def get(self):
        self.write("Hello, world")
        return
 
settings = {
    "cookie_secret": "XmuwPAt8wHdnik4Xvc3GXmbXLifVmPZYhoc9Tx4x1iZ"
}
 
application = tornado.web.Application([
    (r"/", MainHandler)
    ],
    **settings
)
 
if __name__ == "__main__":
    application.listen(8090)
    tornado.ioloop.IOLoop.instance().start()

然后访问 http://localhost:8090/ 就可以访问最简单的网页了

具体的一些简单构建的细节在文档里说的很清楚,我就不累述了

tornado中文入门: http://www.tornadoweb.cn/

tornado中文文档: http://www.tornadoweb.cn/documentation

我主要想记载开发过程中遇到的一些比较技术性的东西

二、用户身份验证

1、一个简单的办法是,根据用户的IP

1
2
# 取得用户的IP地址
self.request.headers.get('X-Real-IP',self.request.remote_ip).decode("utf-8")

2、根据 cookie

上面这个办法当然太简陋了,另外一个办法是通过 cookies

首先要修改 settings

1
2
3
4
settings = {
    "cookie_secret": "XmuwPAt8wHdnik4Xvc3GXmbXLifVmPZYhoc9Tx4x123",
    "login_url": "/login"
}

指定一个加密 cookie 的 secret,再指定一个登陆跳转的页面,当未认证用户尝试登陆需要身份认证的页面的时候就会跳转到这一页面,一般习惯性用 /login

然后给 GET 或 POST 添加一个装饰器

1
2
3
4
5
class MainHandler( BaseHandler ):
    @tornado.web.authenticated
    def get(self):
        self.write("Hello, World")
        return

有了这个装饰器的网页就会要求用户认证身份,认证身份的方法也很简单,注意看 MainHandler 继承于 BaseHandler,这是我自己写的一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
class BaseHandler(tornado.web.RequestHandler):
    def __init__( self, *args, **kwargs ):
        # 继承于 tornado.web.RequestHandler
        tornado.web.RequestHandler.__init__( self, *args, **kwargs )
 
        self.conn = DB()
        self.cursor = self.conn.cursor()
 
    # 这一方法就是 tornado 来判断用户是否已验证的方法
    # 改写这一方法。当返回 True 的时候,tornado就会认为用户已验证
    def get_current_user(self):
        # 我通过返回用户 cookie 的方式来判断是否已验证
        return self.get_secure_cookie("userid")

这时候你就需要有一个登陆页面了,你可以在里面放一个简单的 input 来输入账号密码,然后 POST 给服务器来进行验证,如果通过的话就存入 cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Login( BaseHandler ):
def get(self):
    # 显示登陆页面,等待输入
 
def post(self):
  # 获取用户输入的账号密码
  userid = self.get_argument("userid", strip=True)
  password = self.get_argument("password", strip=True)
 
  # 对账号密码进行验证
 
  # 验证成功后存入cookie
  self.set_secure_cookie("userid", str(userid))
 
  # 这样用户就可以通过 BaseHandler 的检查了

三、静态文件夹

有时候需要用到一些静态文件夹,比如  js、css 和 ico 文件

可以通过在 settings 中增加设置来实现

1
2
3
4
5
6
7
8
9
10
11
settings = {
    # 设置静态文件夹,此处设置为了 ./static
    # 就可以直接访问 http://localhost:8090/static/* 的文件了
    "static_path": os.path.join(pwd, "static"),
    # 设置 cookie_secret
    "cookie_secret": "XmuwPAt8wHdnik4Xvc3GXmbXLifVmPZYhoc9Tx4x1iZ",
    # 设置登录页面
    "login_url": "/login",
    # 是否防跨域 POST (具体见文档)
    "xsrf_cookies": True
}

四:render 的时候将不该显示的 xsrf_form_html() 显示出来了

按照文档设置了 xsrf_cookies: True ,并且在 form 中添加了 {{ xsrf_form_html() }} 后,这条内容却被显示在了网页

这是因为 2.1 之后的 tornado 自动开启了escape,它会自动的将字符符号转义,有两种解决办法,一种是在 HTML 中改写成 {% raw xsrf_form_html() %} 来标明此条语句不转义,另外一种就是在 settings 中将自动转义关掉

1
2
3
4
5
6
7
8
settings = {
    "static_path": os.path.join(pwd, "static"),
    "cookie_secret": "XmuwPAt8wHdnik4Xvc3GXmbXLifVmPZYhoc9Tx4x1iZ",
    "login_url": "/login",
    "xsrf_cookies": True,
    # 关掉自动 escape
    "autoescape":None,
}

五、当 static 文件夹不在本地的时候

static_url 貌似只能解析本地的路径,如果部署在类似 SAE 这样的云平台的时候,代码服务器和存放文件的 Storage 服务器不在一个 domain 上时,static就没法工作了

我的解决办法是自己重写了 tornado.web.RequestHandler 中的 static_url 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class BaseHandler(tornado.web.RequestHandler):
    def __init__( self, *args, **kwargs ):
        tornado.web.RequestHandler.__init__( self, *args, **kwargs )
 
        self.conn = DB()
        self.cursor = self.conn.cursor()
 
 
    def get_current_user(self):
        return self.get_secure_cookie("userid")
 
    # 覆写 static_url 方法,让其解析到文件服务器的地址
    def static_url(self, path, include_host=None, **kwargs):
        self.require_setting("static_path", "static_url")
 
        base = "http://forecastexam-public.stor.sinaapp.com/static/"
 
        return base + path

六、异步操作

可以看看下面这几篇文章

看完这几篇应该大概明白了吧,tornado 是单线程的,要让单线程的效率达到最高,而且不因此而阻塞,最好的办法就是使用异步,异步说白了就是事件驱动,有事(触发)的时候就叫我(callback),没事的时候就 yield 挂着跑别的程序去,不阻塞主线程

tornado 自己带了一个异步的 httpclient ,所以最简单的办法就是把耗时操作单独拿出来放到另外一个 tornado 服务器里,然后用主服务器的 Asynchttpclient 去请求,等数据服务器处理好了返回数据触发 callback

上面的文章里提到了 celery,我没用过 celery,但是 Python 里最常用的异步就是 select 了吧,在 Windows 上只支持 socket,道理同上,把耗时操作放到另外的模块里,然后用 socket 通信传递数据。如果是 epoll 的话,还需要考虑是 level(状态触发) 还是 edge(边缘触发),这个是后话…(我也还在学习中

代码就不贴了,上面的例子里代码挺多了

tornado 杂记的更多相关文章

  1. Python(九)Tornado web 框架

    一.简介 Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过 ...

  2. 使用tornado,我们可以做什么?

    以下介绍都是建立在python2.x的基础上面,tornado使用任意版本皆可. 如果我们需要对外提供一个http server(web api)/websocket server时,我们都可以使用t ...

  3. tornado session

    [转]tornado入门 - session cookie 和session 的区别: 1.cookie数据存放在客户的浏览器上,session数据放在服务器上. 2.cookie不是很安全,别人可以 ...

  4. tornado template

    若果使用Tornado进行web开发可能会用到模板功能,页面继承,嵌套... 多页应用模板的处理多半依赖后端(SPA就可以动态加载局部视图),就算是RESTfull的API设计,也不妨碍同时提供部分模 ...

  5. tornado上手

    http://www.tornadoweb.org/en/stable/ http://www.cnblogs.com/fanweibin/p/5418697.html import tornado. ...

  6. tornado+sqlalchemy+celery,数据库连接消耗在哪里

    随着公司业务的发展,网站的日活数也逐渐增多,以前只需要考虑将所需要的功能实现就行了,当日活越来越大的时候,就需要考虑对服务器的资源使用消耗情况有一个清楚的认知.     最近老是发现数据库的连接数如果 ...

  7. [Erlang 0118] Erlang 杂记 V

       我在知乎回答问题不多,这个问题: "对你职业生涯帮助最大的习惯是什么?它是如何帮助你的?",我还是主动回答了一下.    做笔记 一开始笔记软件做的不好的时候就发邮件给自己, ...

  8. centos 6.7 搭建tornado + nginx + supervisor的方法(已经实践)

    首先,本来不想写这篇博客了,但是我测试了很多网上的例子包括简书的,全不行,我总结原因是自己太笨,搞了俩个晚上,后来决定,自己还是写一篇记录下来,保证自己以后使用 环境: centos6.7 64 py ...

  9. tornado中将cookie值设置为json字符串

    不熟悉,找了很久,能FQ的话, https://groups.google.com/forum/#!topic/python-tornado/9Y--NgwjP_w 2楼有解释. tornado.es ...

随机推荐

  1. JavaScript 不重复的随机数

    在 JavaScript 中,一般产生的随机数会重复,但是有时我们需要不重复的随机数,如何实现?本文给于解决方法,需要的朋友可以参考下     在 JavaScript 中,一般产生的随机数会重复,但 ...

  2. js 数组去重 的5种方法

    一万数组,4个重复项,先贴上成绩. 1.3毫秒 2.115毫秒 3.71毫秒 4.6毫秒 1.哈希表 2.JQuery (最快的方法是用JQuery 这句话是截图带的... 实际上Jq是最慢的) 3. ...

  3. Extjs 实现输入数量,实时更改总价

    // 总价 var totalNum = '0.00'; //总价初始值 var $total = new Ext.form.Label({ text: '消费金额 : ¥' + totalNum + ...

  4. C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem

    class TestThread { static void Main() { //使用WaitHandle静态方法阻止一个线程,直到一个或多个同步对象接收到信号 WaitHandle[] waitH ...

  5. Mac下cocos2dx-3.0打包Android时,提示"SimpleAudioEngine.h"not found的解决方法

    前段时间触控公布cocos2dx-3.0,在升级之后试过之后,在最初的不习惯之后,感觉比之前的好用了不少,在下之前一直是用xCode模板创建,这回算是一口气升到顶了. 之后再一次编程时须要用到Sima ...

  6. shared_ptr注意事项

    对shared_ptr的Copy构造和Copy赋值,会改变引用计数,但是对shared_ptr中原始资源的Copy构造和Copy赋值,不会改变引用计数.因此存在下面的危险情况: 1.获取资源时,初始化 ...

  7. Codeforces Round #181 (Div. 2) A. Array 构造

    A. Array 题目连接: http://www.codeforces.com/contest/300/problem/A Description Vitaly has an array of n ...

  8. Educational Codeforces Round 4 B. HDD is Outdated Technology 暴力

    B. HDD is Outdated Technology 题目连接: http://www.codeforces.com/contest/612/problem/B Description HDD ...

  9. Codeforces Round #136 (Div. 1)C. Little Elephant and Shifts multiset

    C. Little Elephant and Shifts Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/pro ...

  10. openlayers3 在地图上叠加WFS查询矢量图层

    随着终端设备计算能力的加强,用户在使用地图的时候也须要越来越多的交互效果. 比方如今非常火的室内导航,为了获得好的用户体验,就须要当用户单击某一商店的时候该商店的颜色能对应的变化.这就须要叠加矢量图层 ...