tornado学习笔记

学习教材来自于:http://sebug.net/paper/books/tornado/

1. Overriew

    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学习笔记_第1张图片

2. 请求处理程序和请求参数

    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/
浏览器显示如下:

tornado学习笔记_第2张图片

2. 输入输出:

tornado学习笔记_第3张图片

3. 输入错误的地址:

tornado学习笔记_第4张图片

且服务端为:


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()
    浏览器上操作的步骤如下:


tornado学习笔记_第5张图片

    当点击Submit时:

tornado学习笔记_第6张图片

    而我们可以通过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'}]


3. 重写RequestHandler的方法函数

    除了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相关匹配会作为参数传入方法。

//备注:这里不知道如何进行重写


4. 重定向(redirect)

    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学习笔记_第7张图片

5. 模板

    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学习笔记_第8张图片

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

    控制语句和对应的 Python 语句的格式基本完全相同。我们支持if、for、while和try,这些语句逻辑结束的位置需要用{% end %}做标记。

6. Cookie和安全Cookie

    可以使用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()
    连续刷新两次浏览器,则:


tornado学习笔记_第9张图片

tornado学习笔记_第10张图片

    而我们也在firefox中找到了此cookie:

tornado学习笔记_第11张图片

7. 用户认证

    当前已经认证的用户信息被保存在每一个请求处理器的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()


8.跨站伪造请求的防范

    看不懂!后期不断复习的时候,补上。

9. 静态文件和主动式文件缓存

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





你可能感兴趣的:(tornado学习笔记)