[关闭]
@heavysheep 2017-07-17T09:40:12.000000Z 字数 6168 阅读 1307

tornado学习笔记

未分类


第一章

tornado是什么

Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在创始之初就旨在解决C10k问题。
如果当前请求正在等待来自其他资源的数据(比如数据库查询或HTTP请求)时,一个异步服务器可以明确地控制以挂起请求。异步服务器用来恢复暂停的操作的一个常见模式是当合适的数据准备好时调用回调函数。

如何取参

  1. self.get_argument('greeting', 'Hello')

第一个参数为参数名,第二个参数为 参数递补参数

如何分配请求和启动文本服务器

  1. if __name__ == "__main__":
  2. tornado.options.parse_command_line() # 接受命令行参数
  3. app = tornado.web.Application(
  4. handlers=[
  5. (r"/reverse/(\w+)", ReverseHandler), #正则表达式,和调用的类
  6. (r"/wrap", WrapHandler) # 同上
  7. ]
  8. )
  9. http_server = tornado.httpserver.HTTPServer(app) # 将Application对象传递给HTTPServer对象
  10. http_server.listen(options.port) # 通过option对象监听port
  11. tornado.ioloop.IOLoop.instance().start() # 程序启动

状态码处理示例

  1. # matched with (r"/frob/(\d+)", FrobHandler)
  2. class FrobHandler(tornado.web.RequestHandler):
  3. def head(self, frob_id):
  4. frob = retrieve_from_db(frob_id)
  5. if frob is not None: # 如果找到frob_id的头部
  6. self.set_status(200)
  7. else:
  8. self.set_status(404)
  9. def get(self, frob_id):
  10. frob = retrieve_from_db(frob_id)
  11. self.write(frob.serialize())

第二章

模板渲染

  1. if __name__ == '__main__':
  2. tornado.options.parse_command_line()
  3. app = tornado.web.Application(
  4. handlers=[(r'/', IndexHandler), (r'/poem', PoemPageHandler)],
  5. template_path=os.path.join(os.path.dirname(__file__), "templates")
  6. static_path=os.path.join(os.path.dirname(__file__), "static")
  7. )
  8. # template_path参数告诉Tornado在哪里寻找模板文件
  9. # static_path告诉Tornado去哪寻找静态资源如图像、CSS文件、JavaScript文件
  10. http_server = tornado.httpserver.HTTPServer(app)
  11. http_server.listen(options.port)
  12. tornado.ioloop.IOLoop.instance().start()
  1. self.render('index.html') # 渲染模板

模板语法

{{code}}:双大括号代表占位符,可以放变量作为模板的形参,例如:

  1. <p>Two {{roads}} diverged in a {{wood}}</p>
  1. self.render('poem.html', roads=noun1, wood=noun2)

也可使用表达式(注意表达式包括函数),例如:

  1. from tornado.template import Template
  2. print Template("{{ ', '.join([str(x*x) for x in range(10)]) }}").generate()
  3. # 0, 1, 4, 9, 16, 25, 36, 49, 64, 81

{%code%}:代表控制流语句,可以使用Python条件和循环语句,支持if、for、try和while。例如:

  1. <html>
  2. <head>
  3. <title>{{ title }}</title>
  4. </head>
  5. <body>
  6. <h1>{{ header }}</h1>
  7. <ul>
  8. {% for book in books %}
  9. <li>{{ book }}</li>
  10. {% end %}
  11. </ul>
  12. </body>
  13. </html>
  1. class BookHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. self.render(
  4. "book.html",
  5. title="Home Page",
  6. header="Books that are great",
  7. books=[
  8. "Learning Python",
  9. "Programming Collective Intelligence",
  10. "Restful Web Services"
  11. ]
  12. )

模板函数

escape(s):替换字符串s中的&、<、>为他们对应的HTML字符。
url_escape(s):使用urllib.quote_plus替换字符串s中的字符为URL编码形式。
json_encode(val):将val编码成JSON格式。
squeeze(s):过滤字符串s,把连续的多个空白字符替换成一个空格。

static_url生成静态URL

使用static_url函数来生成static目录下文件的URL,示例:

  1. <link rel="stylesheet" href="{{ static_url("style.css") }}">

static_url的好处:
1. static_url函数确保浏览器总是加载一个文件的最新版而不是之前的缓存版本。
2. 修改路径方便,例如将修改默认静态文件static目录为s时,你可以简单地改变静态路径由static变为s,每个使用static_url包裹的引用都会被自动更新,而不必手动修改每个模板。

第三章

块的替换

块的替换也使用控制流语句({% %}),对于一个已经存在的模板,你只需要在新的模板文件的顶部放上一句{% extends "filename.html" %}。比如,在模板index.html中扩展(继承)一个父模板(在这里假设为main.html),你可以这样使用:

  1. {% extends "main.html" %}

当需要覆写多个块时,假设父模板为main.html,例子如下:

  1. <html>
  2. <body>
  3. <header>
  4. {% block header %}{% end %} # block可视为块命名关键字
  5. </header>
  6. <content>
  7. {% block body %}{% end %}
  8. </content>
  9. <footer>
  10. {% block footer %}{% end %}
  11. </footer>
  12. </body>
  13. </html>

子模板为index.html:

  1. {% extends "main.html" %}
  2. {% block header %}
  3. <h1>{{ header_text }}</h1>
  4. {% end %}
  5. {% block body %}
  6. <p>Hello from the child template!</p>
  7. {% end %}
  8. {% block footer %}
  9. <p>{{ footer_text }}</p>
  10. {% end %}

脚本为:

  1. class MainHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. self.render(
  4. "index.html",
  5. header_text = "Header goes here",
  6. footer_text = "Footer goes here"
  7. )

UI模块

为了消除冗余的代码,我们可以使模板部分模块化。比如,展示物品列表的页面可以定位一个单独的模板用来渲染每个物品的标记。另外,一组共用通用导航结构的页面可以从一个共享的模块渲染内容。Tornado的UI模块在这种情况下特别有用。

为了在你的模板中引用模块,你必须在应用的设置中声明它。ui_moudles参数期望一个模块名为键、类为值的字典输入来渲染它们。

实现一个UI模块,首先建立一个UI类

  1. class HelloModule(tornado.web.UIModule): # 建立一个UImodule类,需要先继承UIMoule
  2. def render(self): # 重写render方法
  3. return '<h1>Hello, world!</h1>'

之后在tornado.web.Applicatio的ui_modules中,将module Hello和UI类用字典关联起来

  1. app = tornado.web.Application(
  2. handlers=[(r'/', HelloHandler)],
  3. template_path=os.path.join(os.path.dirname(__file__), 'templates'),
  4. ui_modules={'Hello': HelloModule}
  5. )

最后,UI模块的调用和block略有不同,是函数形式的调用,接受render方法返回的字符串

  1. <html>
  2. <head><title>UI Module Example</title></head>
  3. <body>
  4. {% module Hello() %} # 函数形式的调用,接受render方法返回的字符串
  5. </body>
  6. </html>

在一个例子中提到了UI模块的render_string方法:
render_string:显式地渲染模板文件,当我们返回给调用者时将其关键字参数作为一个字符串。
另外提到了tornado.locale模块提供的日期处理方法:
locale.format_date():默认格式化GMT Unix时间戳为XX time ago,relative=False将使其返回一个绝对时间(包含小时和分钟),而full_format=True选项将会展示一个包含月、日、年和时间的完整日期(比如,July 9, 2011 at 9:47 pm),当搭配shorter=True使用时可以隐藏时间,只显示月、日和年。

该模块还提供字符串时间的支持。

嵌入JavaScript和CSS

注意! 以下方法return的内容都是str格式
嵌入JavaScript方法:

  1. def embedded_javascript(self):
  2. return "document.write(\"hi!\")" # JS方法被插入到<body>的闭标签中

嵌入CSS样式:

  1. def embedded_css(self):
  2. return ".book {background-color:#F5F5F5}" # CSS规则被包裹在<style>中,并被直接添加到<head>的闭标签之前

使用html_body()来在闭合的标签前添加完整的HTML标记(同例1?):

  1. def html_body(self):
  2. return "<script>document.write(\"Hello!\")</script>"

更严谨的样式中,导入CSS文件或JS方法文件

  1. def css_files(self):
  2. return "/static/css/newreleases.css"
  3. def javascript_files(self):
  4. return "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"

** 需要注意的是**
以上的方法都会将内容渲染后插到页面底部,它们出现的顺序正好是你指定它们的顺序的倒序。你不能包括一个需要其他地方东西的方法(比如依赖其他文件的JavaScript函数),因为此时他们可能会按照和你期望不同的顺序进行渲染。

第四章

一个简单的web服务

  1. # 重写了Application
  2. class Application(tornado.web.Application):
  3. def __init__(self):
  4. # 如以往一样的调用,并添加了数据库
  5. handlers = [(r"/(\w+)", WordHandler)]
  6. conn = pymongo.Connection("localhost", 27017)
  7. self.db = conn["example"]
  8. # 注意__init__的使用方法
  9. tornado.web.Application.__init__(self, handlers, debug=True)

第五章

简单的异步请求

  1. class IndexHandler(tornado.web.RequestHandler):
  2. @tornado.web.asynchronous # 使用装饰器来告诉Tornado保持连接开启,以实现异步
  3. def get(self):
  4. query = self.get_argument('q')
  5. client = tornado.httpclient.AsyncHTTPClient()# 实例化一个AsyncHTTPClient()类
  6. client.fetch("http://search.twitter.com/search.json?" + \
  7. urllib.urlencode({"q": query, "result_type": "recent", "rpp": 100}),# 获取远端的接口回调
  8. callback=self.on_response) # AsyncHTTPClient的fetch方法并不返回调用的结果。取而代之的是它指定了一个callback参数;你指定的方法或函数将在HTTP请求完成时被调用,并使用HTTPResponse作为其参数。
  9. def on_response(self, response):
  10. ...
  11. self.finish() # 因为使用异步装饰器后,tornado永远不会主动关闭连接,因此必须使用finish()手动关闭整个连接。

当回调函数可能过多时,我们可以使用gen模块将与请求相关的了逻辑处于同一位置而代码依旧异步,使用方法如下:

  1. python

class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@tornado.gen.engine # 增加gen模块的支持
def get(self):
query = self.get_argument('q')
client = tornado.httpclient.AsyncHTTPClient()
response = yield tornado.gen.Task(client.fetch,
"http://search.twitter.com/search.json?" + \
urllib.urlencode({"q": query, "result_type": "recent", "rpp": 100})) # 使用的yield关以及tornado.gen.Task对象的一个实例,将我们想要的调用和传给该调用函数的参数传递给那个函数,允许在HTTP请求进行中执行其他任务。
self.finish()
```

长轮询

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注