[关闭]
@zhengyuhong 2016-04-08T01:41:48.000000Z 字数 5735 阅读 1576

tornado

posts


install

  1. pip install --user tornado

more info about tornado en
more info about tornado zh

hello world

  1. import sys
  2. import tornado.ioloop
  3. import tornado.web
  4. reload(sys)
  5. sys.setdefaultencoding('utf8')
  6. class MainHandler(tornado.web.RequestHandler):
  7. def get(self):
  8. self.write("hello world")
  9. if __name__ == '__main__':
  10. app = tornado.web.Application([("/", MainHandler)])
  11. app.listen(8080)
  12. tornado.ioloop.IOLoop.instance().start()

打开浏览器输入 http://localhost:8080/ 查看页面。

URL范式映射

  1. import sys
  2. import tornado.ioloop
  3. import tornado.web
  4. reload(sys)
  5. sys.setdefaultencoding('utf8')
  6. class MainHandler(tornado.web.RequestHandler):
  7. def get(self):
  8. self.write("You requestd the main page")
  9. class StoryHandler(tornado.web.RequestHandler):
  10. def get(self, story_id):
  11. self.write("You requested the story %s" % story_id)
  12. if __name__ == '__main__':
  13. app = tornado.web.Application([("/", MainHandler), ('/story/([0-9]+)', StoryHandler)])
  14. #URL 根目录 / 映射到 MainHandler,还将一个 URL 范式 /story/([0-9]+) 映射到 StoryHandler。正则表达式匹配的分组会作为参数引入的相应方法中:
  15. app.listen(8080)
  16. tornado.ioloop.IOLoop.instance().start()

打开浏览器输入 http://localhost:8080/ 查看页面。

RequestHandler.get_argument() 获取参数

  1. class MainHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. self.write('<html><body><form action="/" method="post">'
  4. '<input type="text" name="message">'
  5. '<input type="submit" value="Submit">'
  6. '</form></body></html>')
  7. def post(self):
  8. self.set_header("Content-Type", "text/plain")
  9. self.write("You wrote " + self.get_argument("message"))

使用 get_argument() 方法来获取查询字符串参数,以及解析 GET/POST 的内容

RequestHandler.request

请求处理程序可以通过 (HTTPRequest类)RequestHandler.request 访问到代表当前请求的对象。包含了一些有用的属性,包括:

arguments - 字典,所有的 GET 或 POST 的参数
files - 字典,所有通过 multipart/form-data POST 请求上传的文件
path - str,请求的路径( ? 之前的所有内容)
headers - tornado.httputil.HTTPHeaders,请求的开头信息

RequestHandler.redirect

Tornado 中的重定向有两种主要方法,主要介绍RequestHandler.redirect

self.redirect
RedirectHandler。
你可以在使用 RequestHandler (例如 get)的方法中使用 self.redirect,将用户重定向到别的地方。例如当用户登录后重定向到用户个人主页。

  1. import sys
  2. import tornado.ioloop
  3. import tornado.web
  4. reload(sys)
  5. sys.setdefaultencoding('utf8')
  6. class MainHandler(tornado.web.RequestHandler):
  7. def get(self):
  8. self.redirect('http://www.baidu.com')
  9. if __name__ == '__main__':
  10. app = tornado.web.Application([("/baidu", MainHandler)])
  11. app.listen(8080)
  12. tornado.ioloop.IOLoop.instance().start()

RequestHandler.redirect 通常会被用在自定义方法中get/post等,是由逻辑事件触发 的(例如环境变更、用户认证、以及表单提交)。而 RedirectHandler 是在每次匹配到请求 URL 时被触发。RedirectHandler会在你初始化 Application 时自动生成重定向地址。

RequestHandler.set_cookie

  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!")

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

  1. application = tornado.web.Application([
  2. (r"/", MainHandler),
  3. ], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")

签名过的 cookie 中包含了编码过的 cookie 值,另外还有一个时间戳和一个 HMAC 签名。如果 cookie 已经过期或者 签名不匹配,get_secure_cookie 将返回 None,这和没有设置 cookie 时的 返回值是一样的。上面例子的安全 cookie 版本如下:

  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!")

用户认证

当前已经认证的用户信息被保存在每一个请求处理器的 self.current_user 当中, 同时在模板的 current_user 中也是。默认情况下,current_user 为 None。
要在应用程序实现用户认证的功能,你需要复写请求处理中 get_current_user() 这 个方法,在其中判定当前用户的状态,比如通过 cookie。下面的例子让用户简单地使用一个 nickname 登陆应用,该登陆信息将被保存到 cookie 中

  1. class BaseHandler(tornado.web.RequestHandler):
  2. def get_current_user(self):
  3. return self.get_cookie("user")
  4. class MainHandler(BaseHandler):
  5. def get(self):
  6. if not self.current_user:
  7. self.redirect("/login")
  8. return
  9. name = tornado.escape.xhtml_escape(self.current_user)
  10. self.write("Hello, " + name)
  11. class LoginHandler(BaseHandler):
  12. def get(self):
  13. self.write('<html><body><form action="/login" method="post">'
  14. 'Name: <input type="text" name="name">'
  15. '<input type="submit" value="Sign in">'
  16. '</form></body></html>')
  17. def post(self):
  18. self.set_cookie("user", self.get_argument("name"))
  19. self.redirect("/")
  20. application = tornado.web.Application([
  21. (r"/", MainHandler),
  22. (r"/login", LoginHandler)])

对于那些必须要求用户登陆的操作,可以使用装饰器 tornado.web.authenticated。 如果一个方法套上了这个装饰器,但是当前用户并没有登陆的话,页面会被重定向到 login_url(应用配置中的一个选项),上面的例子可以被改写成:

  1. class BaseHandler(tornado.web.RequestHandler):
  2. def get_current_user(self):
  3. return self.get_secure_cookie("user")
  4. class MainHandler(BaseHandler):
  5. @tornado.web.authenticated
  6. def get(self):
  7. name = tornado.escape.xhtml_escape(self.current_user)
  8. self.write("Hello, " + name)
  9. class LoginHandler(BaseHandler):
  10. def get(self):
  11. self.write('<html><body><form action="/login" method="post">'
  12. 'Name: <input type="text" name="name">'
  13. '<input type="submit" value="Sign in">'
  14. '</form></body></html>')
  15. def post(self):
  16. self.set_secure_cookie("user", self.get_argument("name"))
  17. self.redirect("/")
  18. settings = {
  19. "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
  20. "login_url": "/login",
  21. }
  22. application = tornado.web.Application([
  23. (r"/", MainHandler),
  24. (r"/login", LoginHandler),
  25. ], **settings)

静态文件

通过在应用配置中指定 static_path 选项来提供静态文件服务:

  1. settings = {
  2. "static_path": os.path.join(os.path.dirname(__file__), "static"),
  3. "login_url": "/login",
  4. "template_path": os.path.join(os.path.dirname(__file__),"templates")
  5. }
  6. application = tornado.web.Application([
  7. (r"/", MainHandler),
  8. (r"/login", LoginHandler),
  9. (r"/(apple-touch-icon\.png)", tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
  10. ], **settings)

这样配置后,所有以 /static/ 开头的请求,都会直接访问到指定的静态文件目录, 比如 http://localhost:8888/static/foo.png 会从指定的静态文件目录中访问到 foo.png 这个文件。同时 /robots.txt 和 /favicon.ico 也是会自动作为静态文件处理(即使它们不是以 /static/ 开头)。

调试模式和自动重载

如你将 debug=True 传递给 Application 构造器,该 app 将以调试模式 运行。在调试模式下,模板将不会被缓存,而这个 app 会监视代码文件的修改, 如果发现修改动作,这个 app 就会被重新加载。在开发过程中,这会大大减少 手动重启服务的次数。然而有些问题(例如 import 时的语法错误)还是会让服务器 下线,目前的 debug 模式还无法避免这些情况。

调试模式和 HTTPServer 的多进程模式不兼容。在调试模式下,你必须将 HTTPServer.start 的参数设为不大于 1 的数字。

调试模式下的自动重载功能可以通过独立的模块 tornado.autoreload 调用, 作为测试运行器的一个可选项目,tornado.testing.main 中也有用到它。

本文最新草稿

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