概述

Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像web.py 或者 Google 的 webapp,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具 和优化。

Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题,请参阅 C10K problem。)

下载安装:

1
2
3
4
pip3 install tornado
 
源码安装
https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

总结:

  1. 总结:
  2. 首先可以把多个socket放在一个列表中,循环监听
  3. 1.对于tornado异步非阻塞条件:
  4. tornado帮客户端再一次发一个【IO】请求,才能有异步非阻塞
  5. 2.实现原理:
  6. 创建好服务端后,监听自己的socket,有客户端链接时,再加上监听客户端的socket,帮客户端发送请求时,会相当于在创建一个客户端socket(服务端socket是帮用户要请求的,如百度),
  7. 那么此时的监听的列表 [ 自己的sk,客户端的sk,帮客户端创建的sk]
  8.  
  9. 3.tornado是使用了一个Future对象,来存储每一个帮客户端发送的请求的状态,以及请求的返回值:

  10. 视图Handler里面的yeild的就是一个Future对象,这个对象里面存是帮这个客户端发送请求的状态及返回值,(实例化的时候会把这个客户端对应的回调函数传进去,保证了每一个客户端请求回来的结果可以真确的交给相对应的回调函数)
  11.  
  12. 4.tornado中把每一个客户端来的请求生成的Future对象,存在一个列表中,然后死循环这个列表,监听每一个Future对象里面的状态(self.done,该值默认为False,),当请求结果回来时,就会自动修改这个状态(在函数中self.set_result())设置了self.done=True,当这个状态发送变化时,就去那个监听sk的列表中,取出对应的那个客户端的sk,把值返回回去。

框架使用

一、快速上手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
import tornado.ioloop
import tornado.web
   
   
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
])
   
   
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

执行过程:

  • 第一步:执行脚本,监听 8888 端口
  • 第二步:浏览器客户端访问 /index  -->  http://127.0.0.1:8888/index
  • 第三步:服务器接受请求,并交由对应的类处理该请求
  • 第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
  • 第五步:方法返回值的字符串内容发送浏览器
  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #!/usr/bin/env python
  4. # -*- coding:utf-8 -*-
  5.  
  6. import tornado.ioloop

  7. import tornado.web

  8. from tornado import httpclient

  9. from tornado.web import asynchronous

  10. from tornado import gen
  11.  
  12. import uimodules as md

  13. import uimethods as mt
  14.  
  15. class MainHandler(tornado.web.RequestHandler):

  16. @asynchronous

  17. @gen.coroutine

  18. def get(self):

  19. print 'start get '

  20. http = httpclient.AsyncHTTPClient()

  21. http.fetch("http://127.0.0.1:8008/post/", self.callback)

  22. self.write('end')
  23.     </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> callback(self, response):
  24.         </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> response.body
  25.  
  26. settings = {

  27. 'template_path': 'template',

  28. 'static_path': 'static',

  29. 'static_url_prefix': '/static/',

  30. 'ui_methods': mt,

  31. 'ui_modules': md,

  32. }

  33. application = tornado.web.Application([

  34. (r"/index", MainHandler),

  35. ], **settings)

  36. if name == "main":

  37. application.listen(8009)

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

异步非阻塞示例

二、路由系统

路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
import tornado.ioloop
import tornado.web
   
   
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
   
class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story " + story_id)
   
class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9]+)", StoryHandler),
])
   
application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])
   
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

Tornado中原生支持二级域名的路由,如:

三、模板引擎

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}

控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。这些在 template 模块 的代码文档中有着详细的描述。

注:在使用模板前需要在setting中设置模板路径:"template_path" : "tpl"

1、基本使用

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class MainHandler(tornado.web.RequestHandler):

  8. def get(self):

  9. self.render("index.html", list_info = [11,22,33])
  10.  
  11. application = tornado.web.Application([

  12. (r"/index", MainHandler),

  13. ])
  14.  
  15. if name == "main":

  16. application.listen(8888)

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

app.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  5. <title>老男孩</title>
  6. <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
  7. </head>
  8. <body>
  9. &lt;div&gt;
  10.     &lt;ul&gt;<span style="color: #000000;">
  11.         {</span>% <span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span> list_info %<span style="color: #000000;">}
  12.             </span>&lt;li&gt;{{item}}&lt;/li&gt;<span style="color: #000000;">
  13.         {</span>% end %<span style="color: #000000;">}
  14.     </span>&lt;/ul&gt;
  15. &lt;/div&gt;
  16. &lt;script src=<span style="color: #800000;">"</span><span style="color: #800000;">{{static_url(</span><span style="color: #800000;">"</span>js/jquery-1.8.2.min.js<span style="color: #800000;">"</span><span style="color: #800000;">)}}</span><span style="color: #800000;">"</span>&gt;&lt;/script&gt;
  17.  
  18. </body>

  19. </html>

index.html

  1. 在模板中默认提供了一些函数、字段、类以供模板使用:
  2.  
  3. escape: tornado.escape.xhtml_escape 的別名

  4. xhtml_escape: tornado.escape.xhtml_escape 的別名

  5. url_escape: tornado.escape.url_escape 的別名

  6. json_encode: tornado.escape.json_encode 的別名

  7. squeeze: tornado.escape.squeeze 的別名

  8. linkify: tornado.escape.linkify 的別名

  9. datetime: Python datetime 模组

  10. handler: 当前的 RequestHandler 对象

  11. request: handler.request 的別名

  12. current_user: handler.current_user 的別名

  13. locale: handler.locale 的別名

  14. _: handler.locale.translate 的別名

  15. static_url: for handler.static_url 的別名

  16. xsrf_form_html: handler.xsrf_form_html 的別名

其他方法

2、母版

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  5. <title>老男孩</title>
  6. <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
  7. {% block CSS %}{% end %}
  8. </head>
  9. <body>
  10. <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">div </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="pg-header"</span><span style="color: #0000ff;">&gt;</span>
  11. <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">div</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  12. {% block RenderBody %}{% end %}
  13. </span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">script </span><span style="color: #ff0000;">src</span><span style="color: #0000ff;">="{{static_url("</span><span style="color: #ff0000;">js/jquery-1.8.2.min.js")}}"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">script</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  14. {% block JavaScript %}{% end %}
  15.  
  16. </body>

  17. </html>

layout.html

  1. {% extends 'layout.html'%}
  2. {% block CSS %}
  3. <link href="{{static_url("css/index.css")}}" rel="stylesheet" />
  4. {% end %}
  5.  
  6. {% block RenderBody %}

  7. <h1>Index</h1>
  8. <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">ul</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  9. {%  for item in li %}
  10.     </span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">li</span><span style="color: #0000ff;">&gt;</span>{{item}}<span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">li</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  11. {% end %}
  12. </span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">ul</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  13.  
  14. {% end %}

  15. {% block JavaScript %}

  16. {% end %}

index.html

3、导入

  1. <div>
  2. <ul>
  3. <li>1024</li>
  4. <li>42区</li>
  5. </ul>
  6. </div>

header.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  5. <title>老男孩</title>
  6. <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
  7. </head>
  8. <body>
  9. <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">div </span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">="pg-header"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">
  10.     {% include 'header.html' %}
  11. </span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">div</span><span style="color: #0000ff;">&gt;</span>
  12. <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">script </span><span style="color: #ff0000;">src</span><span style="color: #0000ff;">="{{static_url("</span><span style="color: #ff0000;">js/jquery-1.8.2.min.js")}}"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">script</span><span style="color: #0000ff;">&gt;</span>
  13.  
  14. </body>

  15. </html>

index.html

4、自定义UIMethod以UIModule

a. 定义

  1. # uimethods.py
  2.  
  3. def tab(self):

  4. return 'UIMethod'

uimethods.py

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from tornado.web import UIModule
  4. from tornado import escape
  5.  
  6. class custom(UIModule):
  7. </span><span style="color: #0000ff;">def</span> render(self, *args, **<span style="color: #000000;">kwargs):
  8.     </span><span style="color: #0000ff;">return</span> escape.xhtml_escape(<span style="color: #800000;">'</span><span style="color: #800000;">&lt;h1&gt;wupeiqi&lt;/h1&gt;</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  9.     </span><span style="color: #008000;">#</span><span style="color: #008000;">return escape.xhtml_escape('&lt;h1&gt;wupeiqi&lt;/h1&gt;')</span></pre>
  10.  

uimodules.py

b. 注册

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. #!/usr/bin/env python
  4. # -*- coding:utf-8 -*-
  5.  
  6. import tornado.ioloop

  7. import tornado.web

  8. from tornado.escape import linkify

  9. import uimodules as md

  10. import uimethods as mt
  11.  
  12. class MainHandler(tornado.web.RequestHandler):

  13. def get(self):

  14. self.render('index.html')
  15.  
  16. settings = {

  17. 'template_path': 'template',

  18. 'static_path': 'static',

  19. 'static_url_prefix': '/static/',

  20. 'ui_methods': mt,

  21. 'ui_modules': md,

  22. }
  23.  
  24. application = tornado.web.Application([

  25. (r"/index", MainHandler),

  26. ], **settings)
  27.  
  28. if name == "main":

  29. application.listen(8009)

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

c. 使用

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link href="{{static_url("commons.css")}}" rel="stylesheet" />
  7. </head>
  8. <body>
  9. <h1>hello</h1>
  10. {% module custom(123) %}
  11. {{ tab() }}
  12. </body>

四、静态文件

对于静态文件,可以配置静态文件的目录和前段使用时的前缀,并且Tornaodo还支持静态文件缓存。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class MainHandler(tornado.web.RequestHandler):

  8. def get(self):

  9. self.render('home/index.html')
  10.  
  11. settings = {

  12. 'template_path': 'template',

  13. 'static_path': 'static',

  14. 'static_url_prefix': '/static/',

  15. }
  16.  
  17. application = tornado.web.Application([

  18. (r"/index", MainHandler),

  19. ], **settings)
  20.  
  21. if name == "main":

  22. application.listen(80)

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

app.py

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link href="{{static_url("commons.css")}}" rel="stylesheet" />
  7. </head>
  8. <body>
  9. <h1>hello</h1>
  10. </body>
  11. </html>

index.html

注:静态文件缓存的实现

  1. def get_content_version(cls, abspath):
  2. """Returns a version string for the resource at the given path.
  3.     This class method may be overridden by subclasses.  The
  4.     default implementation is a hash of the file's contents.
  5.     .. versionadded:: 3.1
  6.     </span><span style="color: #800000;">"""</span><span style="color: #000000;">
  7.     data </span>=<span style="color: #000000;"> cls.get_content(abspath)
  8.     hasher </span>=<span style="color: #000000;"> hashlib.md5()
  9.     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(data, bytes):
  10.         hasher.update(data)
  11.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  12.         </span><span style="color: #0000ff;">for</span> chunk <span style="color: #0000ff;">in</span><span style="color: #000000;"> data:
  13.             hasher.update(chunk)
  14.     </span><span style="color: #0000ff;">return</span> hasher.hexdigest()</pre>
  15.  

五、cookie

Tornado中可以对cookie进行操作,并且还可以对cookie进行签名以放置伪造。

1、基本操作

  1. class MainHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. if not self.get_cookie("mycookie"):
  4. self.set_cookie("mycookie", "myvalue")
  5. self.write("Your cookie was not set yet!")
  6. else:
  7. self.write("Your cookie was set!")

2、加密cookie(签名)

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:

  1. class MainHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. if not self.get_secure_cookie("mycookie"):
  4. self.set_secure_cookie("mycookie", "myvalue")
  5. self.write("Your cookie was not set yet!")
  6. else:
  7. self.write("Your cookie was set!")
  8.  
  9. application = tornado.web.Application([

  10. (r"/", MainHandler),

  11. ], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")

  1. def _create_signature_v1(secret, *parts):
  2. hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
  3. for part in parts:
  4. hash.update(utf8(part))
  5. return utf8(hash.hexdigest())
  6.  
  7. # 加密

  8. def _create_signature_v2(secret, s):

  9. hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)

  10. hash.update(utf8(s))

  11. return utf8(hash.hexdigest())
  12.  
  13. def create_signed_value(secret, name, value, version=None, clock=None,

  14. key_version=None):

  15. if version is None:

  16. version = DEFAULT_SIGNED_VALUE_VERSION

  17. if clock is None:

  18. clock = time.time
  19. timestamp </span>=<span style="color: #000000;"> utf8(str(int(clock())))
  20. value </span>=<span style="color: #000000;"> base64.b64encode(utf8(value))
  21. </span><span style="color: #0000ff;">if</span> version == 1<span style="color: #000000;">:
  22.     signature </span>=<span style="color: #000000;"> _create_signature_v1(secret, name, value, timestamp)
  23.     value </span>= b<span style="color: #800000;">"</span><span style="color: #800000;">|</span><span style="color: #800000;">"</span><span style="color: #000000;">.join([value, timestamp, signature])
  24.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> value
  25. </span><span style="color: #0000ff;">elif</span> version == 2<span style="color: #000000;">:
  26.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> The v2 format consists of a version number and a series of</span>
  27.     <span style="color: #008000;">#</span><span style="color: #008000;"> length-prefixed fields "%d:%s", the last of which is a</span>
  28.     <span style="color: #008000;">#</span><span style="color: #008000;"> signature, all separated by pipes.  All numbers are in</span>
  29.     <span style="color: #008000;">#</span><span style="color: #008000;"> decimal format with no leading zeros.  The signature is an</span>
  30.     <span style="color: #008000;">#</span><span style="color: #008000;"> HMAC-SHA256 of the whole string up to that point, including</span>
  31.     <span style="color: #008000;">#</span><span style="color: #008000;"> the final pipe.</span>
  32.     <span style="color: #008000;">#
  33.  
  34. # The fields are:

  35. # - format version (i.e. 2; no length prefix)

  36. # - key version (integer, default is 0)

  37. # - timestamp (integer seconds since epoch)

  38. # - name (not encoded; assumed to be ~alphanumeric)

  39. # - value (base64-encoded)

  40. # - signature (hex-encoded; no length prefix)

  41. def format_field(s):

  42. return utf8("%d:" % len(s)) + utf8(s)

  43. to_sign = b"|".join([

  44. b"",

  45. format_field(str(key_version or 0)),

  46. format_field(timestamp),

  47. format_field(name),

  48. format_field(value),

  49. b''])

  50.     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(secret, dict):
  51.         </span><span style="color: #0000ff;">assert</span> key_version <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span> None, <span style="color: #800000;">'</span><span style="color: #800000;">Key version must be set when sign key dict is used</span><span style="color: #800000;">'</span>
  52.         <span style="color: #0000ff;">assert</span> version &gt;= 2, <span style="color: #800000;">'</span><span style="color: #800000;">Version must be at least 2 for key version support</span><span style="color: #800000;">'</span><span style="color: #000000;">
  53.         secret </span>=<span style="color: #000000;"> secret[key_version]
  54.     signature </span>=<span style="color: #000000;"> _create_signature_v2(secret, to_sign)
  55.     </span><span style="color: #0000ff;">return</span> to_sign +<span style="color: #000000;"> signature
  56. </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  57.     </span><span style="color: #0000ff;">raise</span> ValueError(<span style="color: #800000;">"</span><span style="color: #800000;">Unsupported version %d</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> version)
  58.  
  59. # 解密

  60. def _decode_signed_value_v1(secret, name, value, max_age_days, clock):

  61. parts = utf8(value).split(b"|")

  62. if len(parts) != 3:

  63. return None

  64. signature = _create_signature_v1(secret, name, parts[0], parts[1])

  65. if not _time_independent_equals(parts[2], signature):

  66. gen_log.warning("Invalid cookie signature %r", value)

  67. return None

  68. timestamp = int(parts[1])

  69. if timestamp < clock() - max_age_days * 86400:

  70. gen_log.warning("Expired cookie %r", value)

  71. return None

  72. if timestamp > clock() + 31 * 86400:

  73. # _cookie_signature does not hash a delimiter between the

  74. # parts of the cookie, so an attacker could transfer trailing

  75. # digits from the payload to the timestamp without altering the

  76. # signature. For backwards compatibility, sanity-check timestamp

  77. # here instead of modifying _cookie_signature.

  78. gen_log.warning("Cookie timestamp in future; possible tampering %r",

  79. value)

  80. return None

  81. if parts[1].startswith(b""):

  82. gen_log.warning("Tampered cookie %r", value)

  83. return None

  84. try:

  85. return base64.b64decode(parts[0])

  86. except Exception:

  87. return None

  88. def _decode_fields_v2(value):

  89. def _consume_field(s):

  90. length, _, rest = s.partition(b':')

  91. n = int(length)

  92. field_value = rest[:n]

  93. # In python 3, indexing bytes returns small integers; we must

  94. # use a slice to get a byte string as in python 2.

  95. if rest[n:n + 1] != b'|':

  96. raise ValueError("malformed v2 signed value field")

  97. rest = rest[n + 1:]

  98. return field_value, rest

  99. rest </span>= value[2:]  <span style="color: #008000;">#</span><span style="color: #008000;"> remove version number</span>
  100. key_version, rest =<span style="color: #000000;"> _consume_field(rest)
  101. timestamp, rest </span>=<span style="color: #000000;"> _consume_field(rest)
  102. name_field, rest </span>=<span style="color: #000000;"> _consume_field(rest)
  103. value_field, passed_sig </span>=<span style="color: #000000;"> _consume_field(rest)
  104. </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> int(key_version), timestamp, name_field, value_field, passed_sig
  105.  
  106. def _decode_signed_value_v2(secret, name, value, max_age_days, clock):

  107. try:

  108. key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)

  109. except ValueError:

  110. return None

  111. signed_string = value[:-len(passed_sig)]

  112. </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(secret, dict):
  113.     </span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
  114.         secret </span>=<span style="color: #000000;"> secret[key_version]
  115.     </span><span style="color: #0000ff;">except</span><span style="color: #000000;"> KeyError:
  116.         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  117. expected_sig </span>=<span style="color: #000000;"> _create_signature_v2(secret, signed_string)
  118. </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> _time_independent_equals(passed_sig, expected_sig):
  119.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  120. </span><span style="color: #0000ff;">if</span> name_field !=<span style="color: #000000;"> utf8(name):
  121.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  122. timestamp </span>=<span style="color: #000000;"> int(timestamp)
  123. </span><span style="color: #0000ff;">if</span> timestamp &lt; clock() - max_age_days * 86400<span style="color: #000000;">:
  124.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> The signature has expired.</span>
  125.     <span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  126. </span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
  127.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> base64.b64decode(value_field)
  128. </span><span style="color: #0000ff;">except</span><span style="color: #000000;"> Exception:
  129.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  130.  
  131. def get_signature_key_version(value):

  132. value = utf8(value)

  133. version = _get_version(value)

  134. if version < 2:

  135. return None

  136. try:

  137. key_version, _, _, _, _ = _decode_fields_v2(value)

  138. except ValueError:

  139. return None

  140. </span><span style="color: #0000ff;">return</span> key_version</pre>
  141.  

内部算法

签名Cookie的本质是:

写cookie过程:

  • 将值进行base64加密
  • 对除值以外的内容进行签名,哈希算法(无法逆向解析)
  • 拼接 签名 + 加密值

读cookie过程:

  • 读取 签名 + 加密值
  • 对签名进行验证
  • base64解密,获取值内容

注:许多API验证机制和安全cookie的实现机制相同。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class MainHandler(tornado.web.RequestHandler):
  8. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get(self):
  9.     login_user </span>= self.get_secure_cookie(<span style="color: #800000;">"</span><span style="color: #800000;">login_user</span><span style="color: #800000;">"</span><span style="color: #000000;">, None)
  10.     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> login_user:
  11.         self.write(login_user)
  12.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  13.         self.redirect(</span><span style="color: #800000;">'</span><span style="color: #800000;">/login</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  14.  
  15. class LoginHandler(tornado.web.RequestHandler):

  16. def get(self):

  17. self.current_user()

  18.     self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">login.html</span><span style="color: #800000;">'</span>, **{<span style="color: #800000;">'</span><span style="color: #800000;">status</span><span style="color: #800000;">'</span>: <span style="color: #800000;">''</span><span style="color: #000000;">})
  19. </span><span style="color: #0000ff;">def</span> post(self, *args, **<span style="color: #000000;">kwargs):
  20.     username </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">name</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  21.     password </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  22.     </span><span style="color: #0000ff;">if</span> username == <span style="color: #800000;">'</span><span style="color: #800000;">wupeiqi</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">and</span> password == <span style="color: #800000;">'</span><span style="color: #800000;">123</span><span style="color: #800000;">'</span><span style="color: #000000;">:
  23.         self.set_secure_cookie(</span><span style="color: #800000;">'</span><span style="color: #800000;">login_user</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">武沛齐</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  24.         self.redirect(</span><span style="color: #800000;">'</span><span style="color: #800000;">/</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  25.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  26.         self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">login.html</span><span style="color: #800000;">'</span>, **{<span style="color: #800000;">'</span><span style="color: #800000;">status</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">用户名或密码错误</span><span style="color: #800000;">'</span><span style="color: #000000;">})
  27.  
  28. settings = {

  29. 'template_path': 'template',

  30. 'static_path': 'static',

  31. 'static_url_prefix': '/static/',

  32. 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh'

  33. }

  34. application = tornado.web.Application([

  35. (r"/index", MainHandler),

  36. (r"/login", LoginHandler),

  37. ], **settings)

  38. if name == "main":

  39. application.listen(8888)

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

基于Cookie实现用户验证-Demo

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class BaseHandler(tornado.web.RequestHandler):
  8. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_current_user(self):
  9.     </span><span style="color: #0000ff;">return</span> self.get_secure_cookie(<span style="color: #800000;">"</span><span style="color: #800000;">login_user</span><span style="color: #800000;">"</span><span style="color: #000000;">)
  10.  
  11. class MainHandler(BaseHandler):

  12. @tornado.web.authenticated
  13. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get(self):
  14.     login_user </span>=<span style="color: #000000;"> self.current_user
  15.     self.write(login_user)
  16.  
  17. class LoginHandler(tornado.web.RequestHandler):

  18. def get(self):

  19. self.current_user()

  20.     self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">login.html</span><span style="color: #800000;">'</span>, **{<span style="color: #800000;">'</span><span style="color: #800000;">status</span><span style="color: #800000;">'</span>: <span style="color: #800000;">''</span><span style="color: #000000;">})
  21. </span><span style="color: #0000ff;">def</span> post(self, *args, **<span style="color: #000000;">kwargs):
  22.     username </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">name</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  23.     password </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  24.     </span><span style="color: #0000ff;">if</span> username == <span style="color: #800000;">'</span><span style="color: #800000;">wupeiqi</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">and</span> password == <span style="color: #800000;">'</span><span style="color: #800000;">123</span><span style="color: #800000;">'</span><span style="color: #000000;">:
  25.         self.set_secure_cookie(</span><span style="color: #800000;">'</span><span style="color: #800000;">login_user</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">武沛齐</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  26.         self.redirect(</span><span style="color: #800000;">'</span><span style="color: #800000;">/</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  27.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  28.         self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">login.html</span><span style="color: #800000;">'</span>, **{<span style="color: #800000;">'</span><span style="color: #800000;">status</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">用户名或密码错误</span><span style="color: #800000;">'</span><span style="color: #000000;">})
  29.  
  30. settings = {

  31. 'template_path': 'template',

  32. 'static_path': 'static',

  33. 'static_url_prefix': '/static/',

  34. 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',

  35. 'login_url': '/login'

  36. }

  37. application = tornado.web.Application([

  38. (r"/index", MainHandler),

  39. (r"/login", LoginHandler),

  40. ], **settings)

  41. if name == "main":

  42. application.listen(8888)

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

基于签名Cookie实现用户验证-Demo

3、JavaScript操作Cookie

由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie。

1
2
3
4
5
6
7
8
9
/*
设置cookie,指定秒数过期
 */
function setCookie(name,value,expires){
    var temp = [];
    var current_date = new Date();
    current_date.setSeconds(current_date.getSeconds() + 5);
    document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}

对于参数:

  • domain   指定域名下的cookie
  • path       域名下指定url中的cookie
  • secure    https使用

注:jQuery中也有指定的插件 jQuery Cookie 专门用于操作cookie,猛击这里

六、CSRF

Tornado中的夸张请求伪造和Django中的相似,跨站伪造请求(Cross-site request forgery)

  1. settings = {
  2. "xsrf_cookies": True,
  3. }
  4. application = tornado.web.Application([
  5. (r"/", MainHandler),
  6. (r"/login", LoginHandler),
  7. ], **settings)

配置

  1. <form action="/new_message" method="post">
  2. {{ xsrf_form_html() }}
  3. <input type="text" name="message"/>
  4. <input type="submit" value="Post"/>
  5. </form>

使用 - 普通表单

  1. function getCookie(name) {
  2. var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
  3. return r ? r[1] : undefined;
  4. }
  5.  
  6. jQuery.postJSON = function(url, args, callback) {

  7. args._xsrf = getCookie("_xsrf");

  8. $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST",

  9. success: function(response) {

  10. callback(eval("(" + response + ")"));

  11. }});

  12. };

使用 - AJAX

注:Ajax使用时,本质上就是去获取本地的cookie,携带cookie再来发送请求

七、上传文件

1、Form表单上传

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  5. <title>上传文件</title>
  6. </head>
  7. <body>
  8. <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" >
  9. <input name="fff" id="my_file" type="file" />
  10. <input type="submit" value="提交" />
  11. </form>
  12. </body>
  13. </html>

HTML

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class MainHandler(tornado.web.RequestHandler):

  8. def get(self):
  9.     self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">index.html</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  10. </span><span style="color: #0000ff;">def</span> post(self, *args, **<span style="color: #000000;">kwargs):
  11.     file_metas </span>= self.request.files[<span style="color: #800000;">"</span><span style="color: #800000;">fff</span><span style="color: #800000;">"</span><span style="color: #000000;">]
  12.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> print(file_metas)</span>
  13.     <span style="color: #0000ff;">for</span> meta <span style="color: #0000ff;">in</span><span style="color: #000000;"> file_metas:
  14.         file_name </span>= meta[<span style="color: #800000;">'</span><span style="color: #800000;">filename</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  15.         with open(file_name,</span><span style="color: #800000;">'</span><span style="color: #800000;">wb</span><span style="color: #800000;">'</span><span style="color: #000000;">) as up:
  16.             up.write(meta[</span><span style="color: #800000;">'</span><span style="color: #800000;">body</span><span style="color: #800000;">'</span><span style="color: #000000;">])
  17.  
  18. settings = {

  19. 'template_path': 'template',

  20. }

  21. application = tornado.web.Application([

  22. (r"/index", MainHandler),

  23. ], **settings)

  24. if name == "main":

  25. application.listen(8000)

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

Python

2、AJAX上传

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <input type="file" id="img" />
  9. <input type="button" onclick="UploadFile();" />
  10. <script>
  11. function UploadFile(){
  12. var fileObj = document.getElementById("img").files[0];
  13.         var form </span>=<span style="color: #000000;"> new FormData();
  14.         form.append(</span><span style="color: #800000;">"</span><span style="color: #800000;">k1</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">v1</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  15.         form.append(</span><span style="color: #800000;">"</span><span style="color: #800000;">fff</span><span style="color: #800000;">"</span><span style="color: #000000;">, fileObj);
  16.         var xhr </span>=<span style="color: #000000;"> new XMLHttpRequest();
  17.         xhr.open(</span><span style="color: #800000;">"</span><span style="color: #800000;">post</span><span style="color: #800000;">"</span>, <span style="color: #800000;">'</span><span style="color: #800000;">/index</span><span style="color: #800000;">'</span><span style="color: #000000;">, true);
  18.         xhr.send(form);
  19.     }
  20. </span>&lt;/script&gt;
  21.  
  22. </body>

  23. </html>

HTML - XMLHttpRequest

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <input type="file" id="img" />
  9. <input type="button" onclick="UploadFile();" />
  10. <script>
  11. function UploadFile(){
  12. var fileObj = $("#img")[0].files[0];
  13. var form = new FormData();
  14. form.append("k1", "v1");
  15. form.append("fff", fileObj);
  16.         $.ajax({
  17.             type:</span><span style="color: #800000;">'</span><span style="color: #800000;">POST</span><span style="color: #800000;">'</span><span style="color: #000000;">,
  18.             url: </span><span style="color: #800000;">'</span><span style="color: #800000;">/index</span><span style="color: #800000;">'</span><span style="color: #000000;">,
  19.             data: form,
  20.             processData: false,  </span>// tell jQuery <span style="color: #0000ff;">not</span><span style="color: #000000;"> to process the data
  21.             contentType: false,  </span>// tell jQuery <span style="color: #0000ff;">not</span><span style="color: #000000;"> to set contentType
  22.             success: function(arg){
  23.                 console.log(arg);
  24.             }
  25.         })
  26.     }
  27. </span>&lt;/script&gt;
  28.  
  29. </body>

  30. </html>

HTML - jQuery

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" >
  9. <div id="main">
  10. <input name="fff" id="my_file" type="file" />
  11. <input type="button" name="action" value="Upload" onclick="redirect()"/>
  12. <iframe id='my_iframe' name='my_iframe' src="" class="hide"></iframe>
  13. </div>
  14. </form>
  15. &lt;script&gt;<span style="color: #000000;">
  16.     function redirect(){
  17.         document.getElementById(</span><span style="color: #800000;">'</span><span style="color: #800000;">my_iframe</span><span style="color: #800000;">'</span>).onload =<span style="color: #000000;"> Testt;
  18.         document.getElementById(</span><span style="color: #800000;">'</span><span style="color: #800000;">my_form</span><span style="color: #800000;">'</span>).target = <span style="color: #800000;">'</span><span style="color: #800000;">my_iframe</span><span style="color: #800000;">'</span><span style="color: #000000;">;
  19.         document.getElementById(</span><span style="color: #800000;">'</span><span style="color: #800000;">my_form</span><span style="color: #800000;">'</span><span style="color: #000000;">).submit();
  20.     }
  21.     function Testt(ths){
  22.         var t </span>= $(<span style="color: #800000;">"</span><span style="color: #800000;">#my_iframe</span><span style="color: #800000;">"</span>).contents().find(<span style="color: #800000;">"</span><span style="color: #800000;">body</span><span style="color: #800000;">"</span><span style="color: #000000;">).text();
  23.         console.log(t);
  24.     }
  25. </span>&lt;/script&gt;
  26.  
  27. </body>

  28. </html>

HTML - iframe

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web
  6.  
  7. class MainHandler(tornado.web.RequestHandler):

  8. def get(self):
  9.     self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">index.html</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  10. </span><span style="color: #0000ff;">def</span> post(self, *args, **<span style="color: #000000;">kwargs):
  11.     file_metas </span>= self.request.files[<span style="color: #800000;">"</span><span style="color: #800000;">fff</span><span style="color: #800000;">"</span><span style="color: #000000;">]
  12.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> print(file_metas)</span>
  13.     <span style="color: #0000ff;">for</span> meta <span style="color: #0000ff;">in</span><span style="color: #000000;"> file_metas:
  14.         file_name </span>= meta[<span style="color: #800000;">'</span><span style="color: #800000;">filename</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  15.         with open(file_name,</span><span style="color: #800000;">'</span><span style="color: #800000;">wb</span><span style="color: #800000;">'</span><span style="color: #000000;">) as up:
  16.             up.write(meta[</span><span style="color: #800000;">'</span><span style="color: #800000;">body</span><span style="color: #800000;">'</span><span style="color: #000000;">])
  17.  
  18. settings = {

  19. 'template_path': 'template',

  20. }

  21. application = tornado.web.Application([

  22. (r"/index", MainHandler),

  23. ], **settings)

  24. if name == "main":

  25. application.listen(8000)

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

Python

  1. <script type="text/javascript">
  2. $(document).ready(function () {
  3.     $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#formsubmit</span><span style="color: #800000;">"</span><span style="color: #000000;">).click(function () {
  4.         var iframe </span>= $(<span style="color: #800000;">'</span><span style="color: #800000;">&lt;iframe name="postiframe" id="postiframe" style="display: none"&gt;&lt;/iframe&gt;</span><span style="color: #800000;">'</span><span style="color: #000000;">);
  5.         $(</span><span style="color: #800000;">"</span><span style="color: #800000;">body</span><span style="color: #800000;">"</span><span style="color: #000000;">).append(iframe);
  6.         var form </span>= $(<span style="color: #800000;">'</span><span style="color: #800000;">#theuploadform</span><span style="color: #800000;">'</span><span style="color: #000000;">);
  7.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">action</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">/upload.aspx</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  8.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">method</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">post</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  9.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">encoding</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">multipart/form-data</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  10.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">enctype</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">multipart/form-data</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  11.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">target</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">postiframe</span><span style="color: #800000;">"</span><span style="color: #000000;">);
  12.         form.attr(</span><span style="color: #800000;">"</span><span style="color: #800000;">file</span><span style="color: #800000;">"</span>, $(<span style="color: #800000;">'</span><span style="color: #800000;">#userfile</span><span style="color: #800000;">'</span><span style="color: #000000;">).val());
  13.         form.submit();
  14.         $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#postiframe</span><span style="color: #800000;">"</span><span style="color: #000000;">).load(function () {
  15.             iframeContents </span>=<span style="color: #000000;"> this.contentWindow.document.body.innerHTML;
  16.             $(</span><span style="color: #800000;">"</span><span style="color: #800000;">#textarea</span><span style="color: #800000;">"</span><span style="color: #000000;">).html(iframeContents);
  17.         });
  18.         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> false;
  19.     });
  20. });
  21.  
  22. </script>

  23. <form id="theuploadform">

  24. <input id="userfile" name="userfile" size="" type="file" />

  25. <input id="formsubmit" type="submit" value="Send File" />

  26. </form>

  27. <div id="textarea">

  28. </div>

扩展:基于iframe实现Ajax上传示例

  1. $('#upload_iframe').load(function(){
  2. var iframeContents = this.contentWindow.document.body.innerText;
  3. iframeContents = JSON.parse(iframeContents);
  4.             })</span></pre>
  5.  
  1. function bindChangeAvatar1() {
  2. $('#avatarImg').change(function () {
  3. var file_obj = $(this)[0].files[0];
  4. $('#prevViewImg')[0].src = window.URL.createObjectURL(file_obj)
  5. })
  6. }
  7.     function bindChangeAvatar2() {
  8.         $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#avatarImg</span><span style="color: #800000;">'</span><span style="color: #000000;">).change(function () {
  9.             var file_obj </span>=<span style="color: #000000;"> $(this)[0].files[0];
  10.             var reader </span>=<span style="color: #000000;"> new FileReader();
  11.             reader.readAsDataURL(file_obj);
  12.             reader.onload </span>=<span style="color: #000000;"> function (e) {
  13.                 $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#previewImg</span><span style="color: #800000;">'</span>)[0].src =<span style="color: #000000;"> this.result;
  14.             };
  15.         })
  16.     }
  17.     function bindChangeAvatar3() {
  18.         $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#avatarImg</span><span style="color: #800000;">'</span><span style="color: #000000;">).change(function () {
  19.             var file_obj </span>=<span style="color: #000000;"> $(this)[0].files[0];
  20.             var form </span>=<span style="color: #000000;"> new FormData();
  21.             form.add(</span><span style="color: #800000;">'</span><span style="color: #800000;">img_upload</span><span style="color: #800000;">'</span><span style="color: #000000;">, file_obj);
  22.             $.ajax({
  23.                 url: </span><span style="color: #800000;">''</span><span style="color: #000000;">,
  24.                 data: form,
  25.                 processData: false,  </span>// tell jQuery <span style="color: #0000ff;">not</span><span style="color: #000000;"> to process the data
  26.                 contentType: false,  </span>// tell jQuery <span style="color: #0000ff;">not</span><span style="color: #000000;"> to set contentType
  27.                 success: function (arg) {
  28.                 }
  29.             })
  30.         })
  31.     }
  32.     function bindChangeAvatar4() {
  33.         $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#avatarImg</span><span style="color: #800000;">'</span><span style="color: #000000;">).change(function () {
  34.             $(this).parent().submit();
  35.             $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#upload_iframe</span><span style="color: #800000;">'</span><span style="color: #000000;">).load(function () {
  36.                 var iframeContents </span>=<span style="color: #000000;"> this.contentWindow.document.body.innerText;
  37.                 iframeContents </span>=<span style="color: #000000;"> JSON.parse(iframeContents);
  38.                 </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (iframeContents.status) {
  39.                     $(</span><span style="color: #800000;">'</span><span style="color: #800000;">#previewImg</span><span style="color: #800000;">'</span>).attr(<span style="color: #800000;">'</span><span style="color: #800000;">src</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">/</span><span style="color: #800000;">'</span> +<span style="color: #000000;"> iframeContents.data);
  40.                 }
  41.             })
  42.         })
  43.     }</span></pre>
  44.  

其他

八、验证码

验证码原理在于后台自动创建一张带有随机内容的图片,然后将内容通过img标签输出到页面。

安装图像处理模块:

1
pip3 install pillow

示例截图:

验证码Demo源码下载:猛击这里

九、异步非阻塞

1、基本使用

装饰器 + Future 从而实现Tornado的异步非阻塞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AsyncHandler(tornado.web.RequestHandler):
 
    @gen.coroutine
    def get(self):
        future = Future()
        future.add_done_callback(self.doing)
        yield future
        # 或
        # tornado.ioloop.IOLoop.current().add_future(future,self.doing)
        # yield future
 
    def doing(self,*args, **kwargs):
        self.write('async')
        self.finish()

当发送GET请求时,由于方法被@gen.coroutine装饰且yield 一个 Future对象,那么Tornado会等待,等待用户向future对象中放置数据或者发送信号,如果获取到数据或信号之后,就开始执行doing方法。

异步非阻塞体现在当在Tornaod等待用户向future对象中放置数据时,还可以处理其他请求。

注意:在等待用户向future对象中放置数据或信号时,此连接是不断开的。

2、同步阻塞和异步非阻塞对比

  1. class SyncHandler(tornado.web.RequestHandler):
  2. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get(self):
  3.     self.doing()
  4.     self.write(</span><span style="color: #800000;">'</span><span style="color: #800000;">sync</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  5. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> doing(self):
  6.     time.sleep(</span>10)</pre>
  7.  

同步阻塞

  1. class AsyncHandler(tornado.web.RequestHandler):
  2. @gen.coroutine
  3. def get(self):
  4. future = Future()
  5. tornado.ioloop.IOLoop.current().add_timeout(time.time() + 5, self.doing)
  6. yield future
  7. </span><span style="color: #0000ff;">def</span> doing(self, *args, **<span style="color: #000000;">kwargs):
  8.     self.write(</span><span style="color: #800000;">'</span><span style="color: #800000;">async</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  9.     self.finish()</span></pre>
  10.  

异步非阻塞

3、httpclient类库

Tornado提供了httpclient类库用于发送Http请求,其配合Tornado的异步非阻塞使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
 
import tornado.web
from tornado import gen
from tornado import httpclient
 
# 方式一:
class AsyncHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self, *args, **kwargs):
        print('进入')
        http = httpclient.AsyncHTTPClient()
        data = yield http.fetch("http://www.google.com")
        print('完事',data)
        self.finish('6666')
 
# 方式二:
# class AsyncHandler(tornado.web.RequestHandler):
#     @gen.coroutine
#     def get(self):
#         print('进入')
#         http = httpclient.AsyncHTTPClient()
#         yield http.fetch("http://www.google.com", self.done)
#
#     def done(self, response):
#         print('完事')
#         self.finish('666')
 
 
 
application = tornado.web.Application([
    (r"/async", AsyncHandler),
])
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start() 
  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. """
  4. 需要先安装支持异步操作Mysql的类库:
  5. Tornado-MySQL: https://github.com/PyMySQL/Tornado-MySQL#installation
  6. pip3 install Tornado-MySQL
  7.  
  8. """

  9. import tornado.web

  10. from tornado import gen

  11. import tornado_mysql

  12. from tornado_mysql import pools

  13. POOL = pools.Pool(

  14. dict(host='127.0.0.1', port=3306, user='root', passwd='', db='cmdb'),

  15. max_idle_connections=1,

  16. max_recycle_sec=3)

  17. @gen.coroutine

  18. def get_user_by_conn_pool(user):

  19. cur = yield POOL.execute("SELECT SLEEP(%s)", (user,))

  20. row = cur.fetchone()

  21. raise gen.Return(row)

  22. @gen.coroutine

  23. def get_user(user):

  24. conn = yield tornado_mysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='cmdb',

  25. charset='utf8')

  26. cur = conn.cursor()

  27. # yield cur.execute("SELECT name,email FROM web_models_userprofile where name=%s", (user,))

  28. yield cur.execute("select sleep(10)")

  29. row = cur.fetchone()

  30. cur.close()

  31. conn.close()

  32. raise gen.Return(row)

  33. class LoginHandler(tornado.web.RequestHandler):

  34. def get(self, *args, **kwargs):

  35. self.render('login.html')

  36. @gen.coroutine
  37. </span><span style="color: #0000ff;">def</span> post(self, *args, **<span style="color: #000000;">kwargs):
  38.     user </span>= self.get_argument(<span style="color: #800000;">'</span><span style="color: #800000;">user</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  39.     data </span>= <span style="color: #0000ff;">yield</span><span style="color: #000000;"> gen.Task(get_user, user)
  40.     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> data:
  41.         </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(data)
  42.         self.redirect(</span><span style="color: #800000;">'</span><span style="color: #800000;">http://www.oldboyedu.com</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  43.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  44.         self.render(</span><span style="color: #800000;">'</span><span style="color: #800000;">login.html</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  45.  
  46. application = tornado.web.Application([

  47. (r"/login", LoginHandler),

  48. ])

  49. if name == "main":

  50. application.listen(8888)

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

基于异步非阻塞和Tornado-MySQL实现用户登录示例

自定义Web组件

一、Session

1、面向对象基础

面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ 、__delitem__、__setitem__方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
class Foo(object):
   
    def __getitem__(self, key):
        print  '__getitem__',key
   
    def __setitem__(self, key, value):
        print '__setitem__',key,value
   
    def __delitem__(self, key):
        print '__delitem__',key
   
   
   
obj = Foo()
result = obj['k1']
#obj['k2'] = 'wupeiqi'
#del obj['k1']

2、Tornado扩展

Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BaseHandler(tornado.web.RequestHandler):
   
    def initialize(self):
        self.xxoo = "wupeiqi"
   
   
class MainHandler(BaseHandler):
   
    def get(self):
        print(self.xxoo)
        self.write('index')
 
class IndexHandler(BaseHandler):
   
    def get(self):
        print(self.xxoo)
        self.write('index')

3、session

session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import config
  4. from hashlib import sha1
  5. import os
  6. import time
  7.  
  8. create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest()
  9.  
  10. class SessionFactory:
  11. @staticmethod
  12. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_session_obj(handler):
  13.     obj </span>=<span style="color: #000000;"> None
  14.     </span><span style="color: #0000ff;">if</span> config.SESSION_TYPE == <span style="color: #800000;">"</span><span style="color: #800000;">cache</span><span style="color: #800000;">"</span><span style="color: #000000;">:
  15.         obj </span>=<span style="color: #000000;"> CacheSession(handler)
  16.     </span><span style="color: #0000ff;">elif</span> config.SESSION_TYPE == <span style="color: #800000;">"</span><span style="color: #800000;">memcached</span><span style="color: #800000;">"</span><span style="color: #000000;">:
  17.         obj </span>=<span style="color: #000000;"> MemcachedSession(handler)
  18.     </span><span style="color: #0000ff;">elif</span> config.SESSION_TYPE == <span style="color: #800000;">"</span><span style="color: #800000;">redis</span><span style="color: #800000;">"</span><span style="color: #000000;">:
  19.         obj </span>=<span style="color: #000000;"> RedisSession(handler)
  20.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> obj
  21.  
  22. class CacheSession:

  23. session_container = {}

  24. session_id = "sessionId"

  25. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, handler):
  26.     self.handler </span>=<span style="color: #000000;"> handler
  27.     client_random_str </span>=<span style="color: #000000;"> handler.get_cookie(CacheSession.session_id, None)
  28.     </span><span style="color: #0000ff;">if</span> client_random_str <span style="color: #0000ff;">and</span> client_random_str <span style="color: #0000ff;">in</span><span style="color: #000000;"> CacheSession.session_container:
  29.         self.random_str </span>=<span style="color: #000000;"> client_random_str
  30.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  31.         self.random_str </span>=<span style="color: #000000;"> create_session_id()
  32.         CacheSession.session_container[self.random_str] </span>=<span style="color: #000000;"> {}
  33.     expires_time </span>= time.time() +<span style="color: #000000;"> config.SESSION_EXPIRES
  34.     handler.set_cookie(CacheSession.session_id, self.random_str, expires</span>=<span style="color: #000000;">expires_time)
  35. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__getitem__</span><span style="color: #000000;">(self, key):
  36.     ret </span>=<span style="color: #000000;"> CacheSession.session_container[self.random_str].get(key, None)
  37.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> ret
  38. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__setitem__</span><span style="color: #000000;">(self, key, value):
  39.     CacheSession.session_container[self.random_str][key] </span>=<span style="color: #000000;"> value
  40. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__delitem__</span><span style="color: #000000;">(self, key):
  41.     </span><span style="color: #0000ff;">if</span> key <span style="color: #0000ff;">in</span><span style="color: #000000;"> CacheSession.session_container[self.random_str]:
  42.         </span><span style="color: #0000ff;">del</span><span style="color: #000000;"> CacheSession.session_container[self.random_str][key]
  43.  
  44. class RedisSession:

  45. def init(self, handler):

  46. pass

  47. class MemcachedSession:

  48. def init(self, handler):

  49. pass

自定义Session

4、分布式Session

  1. #!/usr/bin/env python
  2. #coding:utf-8
  3.  
  4. import sys

  5. import math

  6. from bisect import bisect
  7.  
  8. if sys.version_info >= (2, 5):

  9. import hashlib

  10. md5_constructor = hashlib.md5

  11. else:

  12. import md5

  13. md5_constructor = md5.new
  14.  
  15. class HashRing(object):

  16. """一致性哈希"""
  17. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self,nodes):
  18.     </span><span style="color: #800000;">'''</span><span style="color: #800000;">初始化
  19.     nodes : 初始化的节点,其中包含节点已经节点对应的权重
  20.             默认每一个节点有32个虚拟节点
  21.             对于权重,通过多创建虚拟节点来实现
  22.             如:nodes = [
  23.                     {'host':'127.0.0.1:8000','weight':1},
  24.                     {'host':'127.0.0.1:8001','weight':2},
  25.                     {'host':'127.0.0.1:8002','weight':1},
  26.                 ]
  27.     </span><span style="color: #800000;">'''</span><span style="color: #000000;">
  28.     self.ring </span>=<span style="color: #000000;"> dict()
  29.     self._sorted_keys </span>=<span style="color: #000000;"> []
  30.     self.total_weight </span>=<span style="color: #000000;"> 0
  31.     self.</span><span style="color: #800080;">__generate_circle</span><span style="color: #000000;">(nodes)
  32. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__generate_circle</span><span style="color: #000000;">(self,nodes):
  33.     </span><span style="color: #0000ff;">for</span> node_info <span style="color: #0000ff;">in</span><span style="color: #000000;"> nodes:
  34.         self.total_weight </span>+= node_info.get(<span style="color: #800000;">'</span><span style="color: #800000;">weight</span><span style="color: #800000;">'</span>,1<span style="color: #000000;">)
  35.     </span><span style="color: #0000ff;">for</span> node_info <span style="color: #0000ff;">in</span><span style="color: #000000;"> nodes:
  36.         weight </span>= node_info.get(<span style="color: #800000;">'</span><span style="color: #800000;">weight</span><span style="color: #800000;">'</span>,1<span style="color: #000000;">)
  37.         node </span>= node_info.get(<span style="color: #800000;">'</span><span style="color: #800000;">host</span><span style="color: #800000;">'</span><span style="color: #000000;">,None)
  38.         virtual_node_count </span>= math.floor((32*len(nodes)*weight) /<span style="color: #000000;"> self.total_weight)
  39.         </span><span style="color: #0000ff;">for</span> i <span style="color: #0000ff;">in</span><span style="color: #000000;"> xrange(0,int(virtual_node_count)):
  40.             key </span>= self.gen_key_thirty_two( <span style="color: #800000;">'</span><span style="color: #800000;">%s-%s</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> (node, i) )
  41.             </span><span style="color: #0000ff;">if</span> self._sorted_keys.<span style="color: #800080;">__contains__</span><span style="color: #000000;">(key):
  42.                 </span><span style="color: #0000ff;">raise</span> Exception(<span style="color: #800000;">'</span><span style="color: #800000;">该节点已经存在.</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  43.             self.ring[key] </span>=<span style="color: #000000;"> node
  44.             self._sorted_keys.append(key)
  45. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> add_node(self,node):
  46.     </span><span style="color: #800000;">'''</span><span style="color: #800000;"> 新建节点
  47.     node : 要添加的节点,格式为:{'host':'127.0.0.1:8002','weight':1},其中第一个元素表示节点,第二个元素表示该节点的权重。
  48.     </span><span style="color: #800000;">'''</span><span style="color: #000000;">
  49.     node </span>= node.get(<span style="color: #800000;">'</span><span style="color: #800000;">host</span><span style="color: #800000;">'</span><span style="color: #000000;">,None)
  50.     </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> node:
  51.             </span><span style="color: #0000ff;">raise</span> Exception(<span style="color: #800000;">'</span><span style="color: #800000;">节点的地址不能为空.</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  52.     weight </span>= node.get(<span style="color: #800000;">'</span><span style="color: #800000;">weight</span><span style="color: #800000;">'</span>,1<span style="color: #000000;">)
  53.     self.total_weight </span>+=<span style="color: #000000;"> weight
  54.     nodes_count </span>= len(self._sorted_keys) + 1<span style="color: #000000;">
  55.     virtual_node_count </span>= math.floor((32 * nodes_count * weight) /<span style="color: #000000;"> self.total_weight)
  56.     </span><span style="color: #0000ff;">for</span> i <span style="color: #0000ff;">in</span><span style="color: #000000;"> xrange(0,int(virtual_node_count)):
  57.         key </span>= self.gen_key_thirty_two( <span style="color: #800000;">'</span><span style="color: #800000;">%s-%s</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> (node, i) )
  58.         </span><span style="color: #0000ff;">if</span> self._sorted_keys.<span style="color: #800080;">__contains__</span><span style="color: #000000;">(key):
  59.             </span><span style="color: #0000ff;">raise</span> Exception(<span style="color: #800000;">'</span><span style="color: #800000;">该节点已经存在.</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  60.         self.ring[key] </span>=<span style="color: #000000;"> node
  61.         self._sorted_keys.append(key)
  62. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> remove_node(self,node):
  63.     </span><span style="color: #800000;">'''</span><span style="color: #800000;"> 移除节点
  64.     node : 要移除的节点 '127.0.0.1:8000'
  65.     </span><span style="color: #800000;">'''</span>
  66.     <span style="color: #0000ff;">for</span> key,value <span style="color: #0000ff;">in</span><span style="color: #000000;"> self.ring.items():
  67.         </span><span style="color: #0000ff;">if</span> value ==<span style="color: #000000;"> node:
  68.             </span><span style="color: #0000ff;">del</span><span style="color: #000000;"> self.ring[key]
  69.             self._sorted_keys.remove(key)
  70. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_node(self,string_key):
  71.     </span><span style="color: #800000;">'''</span><span style="color: #800000;">获取 string_key 所在的节点</span><span style="color: #800000;">'''</span><span style="color: #000000;">
  72.     pos </span>=<span style="color: #000000;"> self.get_node_pos(string_key)
  73.     </span><span style="color: #0000ff;">if</span> pos <span style="color: #0000ff;">is</span><span style="color: #000000;"> None:
  74.         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  75.     </span><span style="color: #0000ff;">return</span> self.ring[ self._sorted_keys[pos]].split(<span style="color: #800000;">'</span><span style="color: #800000;">:</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  76. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_node_pos(self,string_key):
  77.     </span><span style="color: #800000;">'''</span><span style="color: #800000;">获取 string_key 所在的节点的索引</span><span style="color: #800000;">'''</span>
  78.     <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> self.ring:
  79.         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  80.     key </span>=<span style="color: #000000;"> self.gen_key_thirty_two(string_key)
  81.     nodes </span>=<span style="color: #000000;"> self._sorted_keys
  82.     pos </span>=<span style="color: #000000;"> bisect(nodes, key)
  83.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> pos
  84. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> gen_key_thirty_two(self, key):
  85.     m </span>=<span style="color: #000000;"> md5_constructor()
  86.     m.update(key)
  87.     </span><span style="color: #0000ff;">return</span> long(m.hexdigest(), 16<span style="color: #000000;">)
  88. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> gen_key_sixteen(self,key):
  89.     b_key </span>= self.<span style="color: #800080;">__hash_digest</span><span style="color: #000000;">(key)
  90.     </span><span style="color: #0000ff;">return</span> self.<span style="color: #800080;">__hash_val</span>(b_key, <span style="color: #0000ff;">lambda</span><span style="color: #000000;"> x: x)
  91. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__hash_val</span><span style="color: #000000;">(self, b_key, entry_fn):
  92.     </span><span style="color: #0000ff;">return</span> (( b_key[entry_fn(3)] &lt;&lt; 24)|(b_key[entry_fn(2)] &lt;&lt; 16)|(b_key[entry_fn(1)] &lt;&lt; 8)|<span style="color: #000000;"> b_key[entry_fn(0)] )
  93. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__hash_digest</span><span style="color: #000000;">(self, key):
  94.     m </span>=<span style="color: #000000;"> md5_constructor()
  95.     m.update(key)
  96.     </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> map(ord, m.digest())
  97.  
  98. """

  99. nodes = [

  100. {'host':'127.0.0.1:8000','weight':1},

  101. {'host':'127.0.0.1:8001','weight':2},

  102. {'host':'127.0.0.1:8002','weight':1},

  103. ]

  104. ring = HashRing(nodes)

  105. result = ring.get_node('98708798709870987098709879087')

  106. print result

  107. """

一致性哈西

  1. from hashlib import sha1
  2. import os, time
  3.  
  4. create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
  5.  
  6. class Session(object):
  7. session_id </span>= <span style="color: #800000;">"</span><span style="color: #800000;">__sessionId__</span><span style="color: #800000;">"</span>
  8. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, request):
  9.     session_value </span>=<span style="color: #000000;"> request.get_cookie(Session.session_id)
  10.     </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> session_value:
  11.         self._id </span>=<span style="color: #000000;"> create_session_id()
  12.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  13.         self._id </span>=<span style="color: #000000;"> session_value
  14.     request.set_cookie(Session.session_id, self._id)
  15. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__getitem__</span><span style="color: #000000;">(self, key):
  16.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> 根据 self._id ,在一致性哈西中找到其对应的服务器IP</span>
  17.     <span style="color: #008000;">#</span><span style="color: #008000;"> 找到相对应的redis服务器,如: r = redis.StrictRedis(host='localhost', port=6379, db=0)</span>
  18.     <span style="color: #008000;">#</span><span style="color: #008000;"> 使用python redis api 链接</span>
  19.     <span style="color: #008000;">#</span><span style="color: #008000;"> 获取数据,即:</span>
  20.     <span style="color: #008000;">#</span><span style="color: #008000;"> return self._redis.hget(self._id, name)</span>
  21. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__setitem__</span><span style="color: #000000;">(self, key, value):
  22.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> 根据 self._id ,在一致性哈西中找到其对应的服务器IP</span>
  23.     <span style="color: #008000;">#</span><span style="color: #008000;"> 使用python redis api 链接</span>
  24.     <span style="color: #008000;">#</span><span style="color: #008000;"> 设置session</span>
  25.     <span style="color: #008000;">#</span><span style="color: #008000;"> self._redis.hset(self._id, name, value)</span>
  26. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__delitem__</span><span style="color: #000000;">(self, key):
  27.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> 根据 self._id 找到相对应的redis服务器</span>
  28.     <span style="color: #008000;">#</span><span style="color: #008000;"> 使用python redis api 链接</span>
  29.     <span style="color: #008000;">#</span><span style="color: #008000;"> 删除,即:</span>
  30.     <span style="color: #0000ff;">return</span> self._redis.hdel(self._id, name)</pre>
  31.  

session

二、表单验证

在Web程序中往往包含大量的表单验证的工作,如:判断输入是否为空,是否符合规则。

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link href="{{static_url("commons.css")}}" rel="stylesheet" />
  7. </head>
  8. <body>
  9. <h1>hello</h1>
  10. <form action="/index" method="post">
  11.     &lt;p&gt;hostname: &lt;input type=<span style="color: #800000;">"</span><span style="color: #800000;">text</span><span style="color: #800000;">"</span> name=<span style="color: #800000;">"</span><span style="color: #800000;">host</span><span style="color: #800000;">"</span> /&gt; &lt;/p&gt;
  12.     &lt;p&gt;ip: &lt;input type=<span style="color: #800000;">"</span><span style="color: #800000;">text</span><span style="color: #800000;">"</span> name=<span style="color: #800000;">"</span><span style="color: #800000;">ip</span><span style="color: #800000;">"</span> /&gt; &lt;/p&gt;
  13.     &lt;p&gt;port: &lt;input type=<span style="color: #800000;">"</span><span style="color: #800000;">text</span><span style="color: #800000;">"</span> name=<span style="color: #800000;">"</span><span style="color: #800000;">port</span><span style="color: #800000;">"</span> /&gt; &lt;/p&gt;
  14.     &lt;p&gt;phone: &lt;input type=<span style="color: #800000;">"</span><span style="color: #800000;">text</span><span style="color: #800000;">"</span> name=<span style="color: #800000;">"</span><span style="color: #800000;">phone</span><span style="color: #800000;">"</span> /&gt; &lt;/p&gt;
  15.     &lt;input type=<span style="color: #800000;">"</span><span style="color: #800000;">submit</span><span style="color: #800000;">"</span> /&gt;
  16. &lt;/form&gt;
  17.  
  18. </body>

  19. </html>

HTML

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web

  6. from hashlib import sha1

  7. import os, time

  8. import re
  9.  
  10. class MainForm(object):

  11. def init(self):

  12. self.host = "(.*)"

  13. self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\(</span><span style="color: #800000;">"</span><span style="color: #000000;">
  14. self.port </span>= <span style="color: #800000;">'</span><span style="color: #800000;">(\d+)</span><span style="color: #800000;">'</span><span style="color: #000000;">
  15. self.phone </span>= <span style="color: #800000;">'</span><span style="color: #800000;">^1[3|4|5|8][0-9]\d{8}\)'
  16. <span style="color: #0000ff;">def</span><span style="color: #000000;"> check_valid(self, request):
  17.     form_dict </span>= self.<span style="color: #800080;">__dict__</span>
  18.     <span style="color: #0000ff;">for</span> key, regular <span style="color: #0000ff;">in</span><span style="color: #000000;"> form_dict.items():
  19.         post_value </span>=<span style="color: #000000;"> request.get_argument(key)
  20.         </span><span style="color: #008000;">#</span><span style="color: #008000;"> 让提交的数据 和 定义的正则表达式进行匹配</span>
  21.         ret =<span style="color: #000000;"> re.match(regular, post_value)
  22.         </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> key,ret,post_value
  23.  
  24. class MainHandler(tornado.web.RequestHandler):

  25. def get(self):

  26. self.render('index.html')

  27. def post(self, *args, **kwargs):

  28. obj = MainForm()

  29. result = obj.check_valid(self)

  30. self.write('ok')

  31. settings = {

  32. 'template_path': 'template',

  33. 'static_path': 'static',

  34. 'static_url_prefix': '/static/',

  35. 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',

  36. 'login_url': '/login'

  37. }

  38. application = tornado.web.Application([

  39. (r"/index", MainHandler),

  40. ], **settings)

  41. if name == "main":

  42. application.listen(8888)

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

Python

由于验证规则可以代码重用,所以可以如此定义:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop

  5. import tornado.web

  6. import re
  7.  
  8. class Field(object):
  9. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self, error_msg_dict, required):
  10.     self.id_valid </span>=<span style="color: #000000;"> False
  11.     self.value </span>=<span style="color: #000000;"> None
  12.     self.error </span>=<span style="color: #000000;"> None
  13.     self.name </span>=<span style="color: #000000;"> None
  14.     self.error_msg </span>=<span style="color: #000000;"> error_msg_dict
  15.     self.required </span>=<span style="color: #000000;"> required
  16. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> match(self, name, value):
  17.     self.name </span>=<span style="color: #000000;"> name
  18.     </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> self.required:
  19.         self.id_valid </span>=<span style="color: #000000;"> True
  20.         self.value </span>=<span style="color: #000000;"> value
  21.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  22.         </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> value:
  23.             </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  24.                 self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  25.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  26.                 self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is required</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  27.         </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  28.             ret </span>=<span style="color: #000000;"> re.match(self.REGULAR, value)
  29.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ret:
  30.                 self.id_valid </span>=<span style="color: #000000;"> True
  31.                 self.value </span>=<span style="color: #000000;"> ret.group()
  32.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  33.                 </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  34.                     self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  35.                 </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  36.                     self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is invalid</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  37.  
  38. class IPField(Field):

  39. REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"

  40. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self, error_msg_dict=None, required=<span style="color: #000000;">True):
  41.     error_msg </span>= {}  <span style="color: #008000;">#</span><span style="color: #008000;"> {'required': 'IP不能为空', 'valid': 'IP格式错误'}</span>
  42.     <span style="color: #0000ff;">if</span><span style="color: #000000;"> error_msg_dict:
  43.         error_msg.update(error_msg_dict)
  44.     super(IPField, self).</span><span style="color: #800080;">__init__</span>(error_msg_dict=error_msg, required=<span style="color: #000000;">required)
  45.  
  46. class IntegerField(Field):

  47. REGULAR = "^\d+$"

  48. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self, error_msg_dict=None, required=<span style="color: #000000;">True):
  49.     error_msg </span>= {<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">数字不能为空</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">数字格式错误</span><span style="color: #800000;">'</span><span style="color: #000000;">}
  50.     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> error_msg_dict:
  51.         error_msg.update(error_msg_dict)
  52.     super(IntegerField, self).</span><span style="color: #800080;">__init__</span>(error_msg_dict=error_msg, required=<span style="color: #000000;">required)
  53.  
  54. class CheckBoxField(Field):

  55. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self, error_msg_dict=None, required=<span style="color: #000000;">True):
  56.     error_msg </span>= {}  <span style="color: #008000;">#</span><span style="color: #008000;"> {'required': 'IP不能为空', 'valid': 'IP格式错误'}</span>
  57.     <span style="color: #0000ff;">if</span><span style="color: #000000;"> error_msg_dict:
  58.         error_msg.update(error_msg_dict)
  59.     super(CheckBoxField, self).</span><span style="color: #800080;">__init__</span>(error_msg_dict=error_msg, required=<span style="color: #000000;">required)
  60. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> match(self, name, value):
  61.     self.name </span>=<span style="color: #000000;"> name
  62.     </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> self.required:
  63.         self.id_valid </span>=<span style="color: #000000;"> True
  64.         self.value </span>=<span style="color: #000000;"> value
  65.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  66.         </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> value:
  67.             </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  68.                 self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  69.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  70.                 self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is required</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  71.         </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  72.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(name, list):
  73.                 self.id_valid </span>=<span style="color: #000000;"> True
  74.                 self.value </span>=<span style="color: #000000;"> value
  75.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  76.                 </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  77.                     self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  78.                 </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  79.                     self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is invalid</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  80.  
  81. class FileField(Field):

  82. REGULAR = "^(\w+.pdf)|(\w+.mp3)|(\w+.py)$"

  83. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self, error_msg_dict=None, required=<span style="color: #000000;">True):
  84.     error_msg </span>= {}  <span style="color: #008000;">#</span><span style="color: #008000;"> {'required': '数字不能为空', 'valid': '数字格式错误'}</span>
  85.     <span style="color: #0000ff;">if</span><span style="color: #000000;"> error_msg_dict:
  86.         error_msg.update(error_msg_dict)
  87.     super(FileField, self).</span><span style="color: #800080;">__init__</span>(error_msg_dict=error_msg, required=<span style="color: #000000;">required)
  88. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> match(self, name, value):
  89.     self.name </span>=<span style="color: #000000;"> name
  90.     self.value </span>=<span style="color: #000000;"> []
  91.     </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> self.required:
  92.         self.id_valid </span>=<span style="color: #000000;"> True
  93.         self.value </span>=<span style="color: #000000;"> value
  94.     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  95.         </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> value:
  96.             </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  97.                 self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">required</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  98.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  99.                 self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is required</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  100.         </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  101.             m </span>=<span style="color: #000000;"> re.compile(self.REGULAR)
  102.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(value, list):
  103.                 </span><span style="color: #0000ff;">for</span> file_name <span style="color: #0000ff;">in</span><span style="color: #000000;"> value:
  104.                     r </span>=<span style="color: #000000;"> m.match(file_name)
  105.                     </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> r:
  106.                         self.value.append(r.group())
  107.                         self.id_valid </span>=<span style="color: #000000;"> True
  108.                     </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  109.                         self.id_valid </span>=<span style="color: #000000;"> False
  110.                         </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  111.                             self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  112.                         </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  113.                             self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is invalid</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  114.                         </span><span style="color: #0000ff;">break</span>
  115.             <span style="color: #0000ff;">else</span><span style="color: #000000;">:
  116.                 </span><span style="color: #0000ff;">if</span> self.error_msg.get(<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">, None):
  117.                     self.error </span>= self.error_msg[<span style="color: #800000;">'</span><span style="color: #800000;">valid</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  118.                 </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  119.                     self.error </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s is invalid</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> name
  120. </span><span style="color: #0000ff;">def</span> save(self, request, upload_path=<span style="color: #800000;">""</span><span style="color: #000000;">):
  121.     file_metas </span>=<span style="color: #000000;"> request.files[self.name]
  122.     </span><span style="color: #0000ff;">for</span> meta <span style="color: #0000ff;">in</span><span style="color: #000000;"> file_metas:
  123.         file_name </span>= meta[<span style="color: #800000;">'</span><span style="color: #800000;">filename</span><span style="color: #800000;">'</span><span style="color: #000000;">]
  124.         with open(file_name,</span><span style="color: #800000;">'</span><span style="color: #800000;">wb</span><span style="color: #800000;">'</span><span style="color: #000000;">) as up:
  125.             up.write(meta[</span><span style="color: #800000;">'</span><span style="color: #800000;">body</span><span style="color: #800000;">'</span><span style="color: #000000;">])
  126.  
  127. class Form(object):

  128. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self):
  129.     self.value_dict </span>=<span style="color: #000000;"> {}
  130.     self.error_dict </span>=<span style="color: #000000;"> {}
  131.     self.valid_status </span>=<span style="color: #000000;"> True
  132. </span><span style="color: #0000ff;">def</span> validate(self, request, depth=10, pre_key=<span style="color: #800000;">""</span><span style="color: #000000;">):
  133.     self.initialize()
  134.     self.</span><span style="color: #800080;">__valid</span><span style="color: #000000;">(self, request, depth, pre_key)
  135. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> initialize(self):
  136.     </span><span style="color: #0000ff;">pass</span>
  137. <span style="color: #0000ff;">def</span> <span style="color: #800080;">__valid</span><span style="color: #000000;">(self, form_obj, request, depth, pre_key):
  138.     </span><span style="color: #800000;">"""</span><span style="color: #800000;">
  139.     验证用户表单请求的数据
  140.     :param form_obj: Form对象(Form派生类的对象)
  141.     :param request: Http请求上下文(用于从请求中获取用户提交的值)
  142.     :param depth: Form内容的深度的支持
  143.     :param pre_key: Htmlname属性值的前缀(多层Form时,内部递归时设置,无需理会)
  144.     :return: 是否验证通过,True:验证成功;False:验证失败
  145.     </span><span style="color: #800000;">"""</span><span style="color: #000000;">
  146.     depth </span>-= 1
  147.     <span style="color: #0000ff;">if</span> depth &lt;<span style="color: #000000;"> 0:
  148.         </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
  149.     form_field_dict </span>= form_obj.<span style="color: #800080;">__dict__</span>
  150.     <span style="color: #0000ff;">for</span> key, field_obj <span style="color: #0000ff;">in</span><span style="color: #000000;"> form_field_dict.items():
  151.         </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> key,field_obj
  152.         </span><span style="color: #0000ff;">if</span> isinstance(field_obj, Form) <span style="color: #0000ff;">or</span><span style="color: #000000;"> isinstance(field_obj, Field):
  153.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(field_obj, Form):
  154.                 </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取以key开头的所有的值,以参数的形式传至</span>
  155.                 self.<span style="color: #800080;">__valid</span><span style="color: #000000;">(field_obj, request, depth, key)
  156.                 </span><span style="color: #0000ff;">continue</span>
  157.             <span style="color: #0000ff;">if</span><span style="color: #000000;"> pre_key:
  158.                 key </span>= <span style="color: #800000;">"</span><span style="color: #800000;">%s.%s</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> (pre_key, key)
  159.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(field_obj, CheckBoxField):
  160.                 post_value </span>=<span style="color: #000000;"> request.get_arguments(key, None)
  161.             </span><span style="color: #0000ff;">elif</span><span style="color: #000000;"> isinstance(field_obj, FileField):
  162.                 post_value </span>=<span style="color: #000000;"> []
  163.                 file_list </span>=<span style="color: #000000;"> request.request.files.get(key, None)
  164.                 </span><span style="color: #0000ff;">for</span> file_item <span style="color: #0000ff;">in</span><span style="color: #000000;"> file_list:
  165.                     post_value.append(file_item[</span><span style="color: #800000;">'</span><span style="color: #800000;">filename</span><span style="color: #800000;">'</span><span style="color: #000000;">])
  166.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  167.                 post_value </span>=<span style="color: #000000;"> request.get_argument(key, None)
  168.             </span><span style="color: #0000ff;">print</span><span style="color: #000000;"> post_value
  169.             </span><span style="color: #008000;">#</span><span style="color: #008000;"> 让提交的数据  定义的正则表达式进行匹配</span>
  170.  
  171. field_obj.match(key, post_value)

  172. if field_obj.id_valid:

  173. self.value_dict[key] = field_obj.value

  174. else:

  175. self.error_dict[key] = field_obj.error

  176. self.valid_status = False

  177. class ListForm(object):

  178. def init(self, form_type):

  179. self.form_type = form_type

  180. self.valid_status = True

  181. self.value_dict = {}

  182. self.error_dict = {}

  183. </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> validate(self, request):
  184.     name_list </span>= request.request.arguments.keys() +<span style="color: #000000;"> request.request.files.keys()
  185.     index </span>=<span style="color: #000000;"> 0
  186.     flag </span>=<span style="color: #000000;"> False
  187.     </span><span style="color: #0000ff;">while</span><span style="color: #000000;"> True:
  188.         pre_key </span>= <span style="color: #800000;">"</span><span style="color: #800000;">[%d]</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> index
  189.         </span><span style="color: #0000ff;">for</span> name <span style="color: #0000ff;">in</span><span style="color: #000000;"> name_list:
  190.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> name.startswith(pre_key):
  191.                 flag </span>=<span style="color: #000000;"> True
  192.                 </span><span style="color: #0000ff;">break</span>
  193.         <span style="color: #0000ff;">if</span><span style="color: #000000;"> flag:
  194.             form_obj </span>=<span style="color: #000000;"> self.form_type()
  195.             form_obj.validate(request, depth</span>=10, pre_key=<span style="color: #800000;">"</span><span style="color: #800000;">[%d]</span><span style="color: #800000;">"</span> %<span style="color: #000000;"> index)
  196.             </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> form_obj.valid_status:
  197.                 self.value_dict[index] </span>=<span style="color: #000000;"> form_obj.value_dict
  198.             </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  199.                 self.error_dict[index] </span>=<span style="color: #000000;"> form_obj.error_dict
  200.                 self.valid_status </span>=<span style="color: #000000;"> False
  201.         </span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
  202.             </span><span style="color: #0000ff;">break</span><span style="color: #000000;">
  203.         index </span>+= 1<span style="color: #000000;">
  204.         flag </span>=<span style="color: #000000;"> False
  205.  
  206. class MainForm(Form):

  207. </span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self):
  208.     </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.ip = IPField(required=True)</span>
  209.     <span style="color: #008000;">#</span><span style="color: #008000;"> self.port = IntegerField(required=True)</span>
  210.     <span style="color: #008000;">#</span><span style="color: #008000;"> self.new_ip = IPField(required=True)</span>
  211.     <span style="color: #008000;">#</span><span style="color: #008000;"> self.second = SecondForm()</span>
  212.     self.fff = FileField(required=<span style="color: #000000;">True)
  213.     super(MainForm, self).</span><span style="color: #800080;">__init__</span><span style="color: #000000;">()
  214.  
  215. #

  216. class SecondForm(Form):

  217. def init(self):

  218. self.ip = IPField(required=True)

  219. self.new_ip = IPField(required=True)

  220. super(SecondForm, self).init()

  221. class MainHandler(tornado.web.RequestHandler):

  222. def get(self):

  223. self.render('index.html')

  224. def post(self, *args, **kwargs):

  225. # for i in dir(self.request):

  226. # print i

  227. # print self.request.arguments

  228. # print self.request.files

  229. # print self.request.query

  230. # name_list = self.request.arguments.keys() + self.request.files.keys()

  231. # print name_list

  232.     <span style="color: #008000;">#</span><span style="color: #008000;"> list_form = ListForm(MainForm)</span>
  233.     <span style="color: #008000;">#</span><span style="color: #008000;"> list_form.validate(self)</span>
  234.     <span style="color: #008000;">#
  235.  
  236. # print list_form.valid_status

  237. # print list_form.value_dict

  238. # print list_form.error_dict

  239.     <span style="color: #008000;">#</span><span style="color: #008000;"> obj = MainForm()</span>
  240.     <span style="color: #008000;">#</span><span style="color: #008000;"> obj.validate(self)</span>
  241.     <span style="color: #008000;">#
  242.  
  243. # print "验证结果:", obj.valid_status

  244. # print "符合验证结果:", obj.value_dict

  245. # print "错误信息:"

  246. # for key, item in obj.error_dict.items():

  247. # print key,item

  248. # print self.get_arguments('favor'),type(self.get_arguments('favor'))

  249. # print self.get_argument('favor'),type(self.get_argument('favor'))

  250. # print type(self.get_argument('fff')),self.get_argument('fff')

  251. # print self.request.files

  252. # obj = MainForm()

  253. # obj.validate(self)

  254. # print obj.valid_status

  255. # print obj.value_dict

  256. # print obj.error_dict

  257. # print self.request,type(self.request)

  258. # obj.fff.save(self.request)

  259. # from tornado.httputil import HTTPServerRequest

  260. # name_list = self.request.arguments.keys() + self.request.files.keys()

  261. # print name_list

  262. # print self.request.files,type(self.request.files)

  263. # print len(self.request.files.get('fff'))

  264.     <span style="color: #008000;">#</span><span style="color: #008000;"> obj = MainForm()</span>
  265.     <span style="color: #008000;">#</span><span style="color: #008000;"> obj.validate(self)</span>
  266.     <span style="color: #008000;">#</span><span style="color: #008000;"> print obj.valid_status</span>
  267.     <span style="color: #008000;">#</span><span style="color: #008000;"> print obj.value_dict</span>
  268.     <span style="color: #008000;">#</span><span style="color: #008000;"> print obj.error_dict</span>
  269.     <span style="color: #008000;">#</span><span style="color: #008000;"> obj.fff.save(self.request)</span>
  270.     self.write(<span style="color: #800000;">'</span><span style="color: #800000;">ok</span><span style="color: #800000;">'</span><span style="color: #000000;">)
  271.  
  272. settings = {

  273. 'template_path': 'template',

  274. 'static_path': 'static',

  275. 'static_url_prefix': '/static/',

  276. 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',

  277. 'login_url': '/login'

  278. }

  279. application = tornado.web.Application([

  280. (r"/index", MainHandler),

  281. ], **settings)

  282. if name == "main":

  283. application.listen(8888)

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

Tornado(1)的更多相关文章

  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. centos 6.7 搭建tornado + nginx + supervisor的方法(已经实践)

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

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

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

  9. tornado 异步调用系统命令和非阻塞线程池

    项目中异步调用 ping 和 nmap 实现对目标 ip 和所在网关的探测 Subprocess.STREAM 不用担心进程返回数据过大造成的死锁, Subprocess.PIPE 会有这个问题. i ...

  10. 离线安装 Python 2.7, paramiko 和 tornado

    无非就是离线安装, 步骤比较繁琐, 记录一下. 需求很简单, 一个离线安装的 Python, 能跑 tornado 和 paramiko 1. 离线安装 Python 2.7 .tgz cd Pyth ...

随机推荐

  1. 从零开始手写 dubbo rpc 框架

    rpc rpc 是基于 netty 实现的 java rpc 框架,类似于 dubbo. 主要用于个人学习,由渐入深,理解 rpc 的底层实现原理. 前言 工作至今,接触 rpc 框架已经有很长时间. ...

  2. 【重要更新】Senparc.Weixin SDK v6.5 升级说明(支持 .NET Core 3.0 及分布式消息上下文)

    Senparc.Weixin SDK v6.5 开始支持 .NET Core 3.0,并将微信消息上下文进行了大幅度的重构,支持了使用分布式缓存存储上下文信息,这意味着在分布式系统中,现在 Senpa ...

  3. C# 打开文件/跳转链接

    mark一下~ 打开文件 1.打开文件夹: System.Diagnostics.Process.Start(FolderPath);-- 打开文件夹 System.Diagnostics.Proce ...

  4. git命令行的颜色配置

    Git颜色branch,diff,interactive,status配置,git终端配置颜色,git命令行高亮 Git默认的输出是单一颜色的,感觉很不容易阅读,Git支持用多种颜色来显示其输出的信息 ...

  5. 设置自动获取IP和DNS

    问题阐述 设置ipv4的自动获取时遇到一个问题,ip和dns自动获取可以确认设置,但是全局时就是报错,回头去看ipv4的ip和dns也还是原来的样子 由于一直使用的都是自动获取,很少会有主动设置ip或 ...

  6. Navicat Premium 连接oracle 提示ORA-01017:用户名/口令无效;登陆被拒绝

    Navicat Premium 连接oracle,密码明明是对的,还是提示 ORA-01017:用户名/口令无效:登陆被拒绝.而用Pl/SQL 连接没有问题. 其实用户名和密码是对的,但还是会报错,这 ...

  7. [译]Vulkan教程(03)开发环境

    [译]Vulkan教程(03)开发环境 这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第3篇. In this chapter we'll set up y ...

  8. C语言程序设计100例之(20):过河卒

    例20  过河卒 题目描述 如图1,在棋盘的A点有一个过河卒,需要走到目标B点.卒行走规则:可以向下.或者向右.同时在棋盘上的任一点有一个对方的马(如图1的C点),该马所在的点和所有跳跃一步可达的点称 ...

  9. Python深拷贝与浅拷贝区别

    可变类型 如list.dict等类型,改变容器内的值,容器地址不变. 不可变类型 如元组.字符串,原则上不可改变值.如果要改变对象的值,是将对象指向的地址改变了 浅拷贝 对于可变对象来说,开辟新的内存 ...

  10. Java连接数据库 #07# MyBatis Generator简单例子

    MyBatis Generator是一个可以帮助我们免去手写实体类&接口类以及XML的代码自动生成工具. 下面,通过一个简单的例子介绍MyBatis Generator如何使用. 大体流程如下 ...