学习教材来自于:http://sebug.net/paper/books/tornado/
Tornado是非阻塞式服务器,得利于其非阻塞式和对epoll的运用。以下为经典的hello world:
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()这里,我们在浏览器中输入:localhost:8888/,则界面显示如下:
Tornado的web程序会将URL或者URL范式映射到tornado.web.RequestHandler的子类上去。在其子类中定义了get()或post()方法,用以处理不同的HTTP请求。
以下代码将URL根目录/映射到MainHandler,还将一个URL范式/story/([0-9]+)映射到StoryHandler.正则表达式匹配的分组会作为参数引入的相应方法中:
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("You requested the main page") class StoryHandler(tornado.web.RequestHandler): def get(self, story_id): self.write("You requested the story " + story_id) application = tornado.web.Application([ (r"/", MainHandler), (r"/story/([0-9]+)", StoryHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()1. 输入
http://localhost:8888/浏览器显示如下:
2. 输入输出:
3. 输入错误的地址:
且服务端为:
leichaojian@leichaojian-ThinkPad-T430:~/tornado-2.0$ python test.py WARNING:root:404 GET /story/1234-123 (127.0.0.1) 0.29ms而我们可以通过get_argument()方法来获取查询字符串参数,以及解析POST的内容:
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write('<html><body><form action="/" method="post">' '<input type="text" name="message">' '<input type="submit" value="Submit">' '</form></body></html>') def post(self): self.set_header("Content-Type", "text/plain") self.write("You wrote " + self.get_argument("message")) application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()浏览器上操作的步骤如下:
当点击Submit时:
而我们可以通过self.request.files访问到上传的文件,该对象将名称(HTML元素<input type="file">的name属性)对应到一个文件列表。每个文件都以字典的形式存在,其格式为{"filename":...,"content_type":...,"body":...}
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write('<html><body><form action="" enctype="multipart/form-data" method="post">' '<input type="file" name="myfile">' '<input type="file" name="myfile">' '<input type="submit" value="Submit">' '</form></body></html>') def post(self): print(self.request.files["myfile"]) application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()当我在浏览器上选择文件提交后,(选择文件test.txt,里面只有一行:hello world),服务端显示:
leichaojian@leichaojian-ThinkPad-T430:~/tornado-1.2.1$ python test.py [{'body': 'hello world\n', 'content_type': 'text/plain', 'filename': u'test.txt'}]
除了get()/post()等以外,RequestHandler中的一些别的方法函数,这都是一些空函数,它们存在的目的是在必要时在子类中重新定义其内容。对于一个请求的处理的代码调用次序如下:
1. 程序为每一个请求创建一个RequestHandler对象
2. 程序调用initialize()函数,这个函数的参数是Application配置的关键字参数定义。initialize方法一般只是把传入的参数存到成员变量中,而不会产生一些输出或者调用像send_error之类的方法。
3. 程序调用prepare()。无论使用了哪种HTTP方法,prepare都会被调用到,因此这个方法通常会被定义在一个基类中,然后在子类中重用。prepare可以产生输出信息。如果它调用了finish(或send_error等函数),name整个处理流程就此结束。
4. 程序调用某个HTTP方法:如get(),post(),put()等。如果URL的正则表达式中有分组匹配,name相关匹配会作为参数传入方法。
//备注:这里不知道如何进行重写
Tornado 中的重定向有两种主要方法:self.redirect,或者使用RedirectHandler。
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write('<html><body><form action="/" method="post">' '<input type="text" name="url">' '<input type="submit" value="Submit">' '</form></body></html>') def post(self): self.redirect(self.get_argument("url"), permanent=True) application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()但是,当我在页面输入test.html时候,是正确的进行了重定向,但是我却不知道localhost/test.html的路径在哪里:
Tornado模板其实就是HTML文件,其中包含了python控制结构和表达式,这些控制结构和表达式需要放在规定的格式标识符(markup)中:
template.html:
<html> <head> <title>{{ title }}</title> </head> <body> <ul> {% for item in items %} <li>{{ escape(item) }}</li> {% end %} </ul> </body> </html>而我们编写如下代码:
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): items = ["Item1", "Item2", "Item3"] self.render("template.html", title="my title", items=items) application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()则浏览器显示如下:
Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用{%和%}包起来的 例如{% if len(items) > 2 %}。表达语句是使用{{和}}包起来的,例如{{ items[0] }}。
控制语句和对应的 Python 语句的格式基本完全相同。我们支持if、for、while和try,这些语句逻辑结束的位置需要用{% end %}做标记。
可以使用set_cookie方法在用户的浏览器中设置cookie:
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): if not self.get_secure_cookie("mycookie"): self.set_secure_cookie("mycookie", "myvalue") self.write("Your cookie was not set yet!") else: self.write("Your cookie was set!") application = tornado.web.Application([ (r"/", MainHandler), ], cookie_secret="ETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=") if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()连续刷新两次浏览器,则:
而我们也在firefox中找到了此cookie:
当前已经认证的用户信息被保存在每一个请求处理器的self.current_user当中,同时在模板current_user中也是。默认情况下,current_user为None.
要在应用程序实现用户认证,你需要复写请求处理中get_current_user()这个方法,在其中判断当前用户的状态,比如通过cookie:
import tornado.ioloop import tornado.web class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("user") class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): name = tornado.escape.xhtml_escape(self.current_user) self.write("Hello, " + name) class LoginHandler(BaseHandler): def get(self): self.write('<html><body><form action="/login" method="post">' 'Name: <input type="text" name="name">' '<input type="submit" value="Sign in">' '</form></body></html>') def post(self): self.set_secure_cookie("user", self.get_argument("name")) self.redirect("/") settings = { "cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=", "login_url": "/login", } application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
看不懂!后期不断复习的时候,补上。
你能通过在应用配置中指定static_path选项来提供静态文件服务: