Tornado应用笔记02-Web框架

索引

  • 01-简介
  • => 02-Web框架
  • 03-协程与异步示例
  • 04-浅析源码
  • 05-异步客户端
  • 06-WebSocket与长轮询

本节内容围绕Tornado的Web框架部分展开, 主要介绍Tornado在Web框架部分中使用频率最高的RequestHandler, 同时也包括Application等其余相关内容.

RequestHandler

作为每一个HTTP请求的"必经之地", 一个请求在RequestHandler内的大致处理流程如下:

  1. 根据正则匹配创建相应RequestHandler
  2. .initialize()初始化
  3. .prepare()准备
  4. 根据请求的http verb method进入相应入口, 如.get() .post()
  5. .finish()完成请求
  6. .on_finish()后续操作

(注: 这个流程是不够严谨的, 只是希望读者对此能先有个大概的认识)

RequestHandler内的方法可以划分成以下几类: 入口, 输入, 输出, Cookie和其他, 这里只分析其中最常用的方法, 如果想要了解全部内容则需要查阅官方文档.

入口(参考链接):

.initialize()

进行初始化工作, 可以接收来自注册路由时传递的参数. 虽然这里也可以做输出操作, 但是并不建议这么做, 输出操作放到.prepare()会使逻辑更清晰.


.prepare()

可以理解为一个请求"真正"的开始, 主要用来处理一些请求的准备工作, 比如预处理请求, 也可以做输出操作. 完成以后进入到.get() .post()等. 需要注意的是, 如果在这里结束请求, 如调用.finish()等, 那就不会执行.get() .post()等. 有一个比较有意思的点是.prepare()是可以"异步"的, 更准确的说法应该是可以"协程化", 通过@gen.coroutine@return_future可以实现(不能使用@asynchronous). 关于Tornado实现协程和异步的方法, 后续会有文章深入探讨, 这里就不展开说了.


.on_finish()

请求完成后自动调用(实际上是由.finish()调用的), 可以根据需要做一些释放资源或写日志等操作. 注意, 这里是不能进行输出操作的.

默认支持的http verb method
.get() .post() .put() .patch() .delete() .head() .options()


跑一个例子能更好的理解这个流程

# -*- coding: utf-8 -*-
# file: request_entry_point.py

import tornado.ioloop
import tornado.web


class BaseHandler(tornado.web.RequestHandler):
    # 扩展默认http方法的办法
    SUPPORTED_METHODS = tornado.web.RequestHandler.SUPPORTED_METHODS + ('PROPFIND',)

    def initialize(self, **kwargs):
        print 'into initialize'
        self._id = kwargs.get('id', -1)

    def prepare(self):
        print 'into prepare'

    def on_finish(self):
        print 'into finish'
        self.release_resource()

    def release_resource(self):
        pass

    def get(self, *args, **kwargs):
        print 'into get'
        arg = args[0] or None
        self.write('a get request, the re arg is |%s|' % arg)

    def propfind(self, *args, **kwargs):
        print 'into extra method propfind'
        self.write('a propfind request')


def make_app():
    return tornado.web.Application([
        # 正则匹配的参数会传入http方法中
        (r"/(.*)", BaseHandler, {'id': '123456'}),
    ])


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print 'Tornado server is running at localhost:8888'
    tornado.ioloop.IOLoop.current().start()

输入(参考链接):

请求参数
.get_argument() .get_arguments()

bodyurl中获取参数(参数都是unicode编码的), 两者不同点在于.get_arguments()返回的是参数列表, 而.get_argument()返回参数列表的最后一个参数, 并且.get_argument()会在目标参数不存在的时候抛出MissingArgumentError异常.


.get_query_argument() .get_query_arguments()

url中获取参数, 区别参考.get_argument() .get_arguments()


.get_body_argument() .get_body_arguments()

body中获取参数, 区别参考.get_argument() .get_arguments()


.get_json()

实际上, Tornado并未直接提供获取json格式数据的方法, 如果有需要的话, 可以参考下面这段代码

def get_json(self):
    import json
    content_type = self.request.headers.get('Content-Type')
    if content_type and content_type.lower().startswith('application/json'):
        try:
            return json.loads(self.request.body)
        except ValueError:
            pass
    raise Exception('get json fail, please check content-type |%s| & body |%s|' % (content_type, body))
请求信息
.request

.request实际上是一个HTTPServerRequest对象, 包含method uri query version headers body remote_ip protocol host arguments query_arguments body_arguments files connection cookies full_url() request_time().

这里只介绍headersfiles(cookies放在后面与相关方法一起介绍), 其余的可以参考官方文档, 又或是print出来看看是什么.

在上传文件时(Content-Type: multipart/form-data; boundary=----WebKitFormBoundary*random_string*), 文件变为HTTPFile对象

# .request.files的结构
{
    'arg_name': [
        {
            'body': '********',
            'content_type': 'image/png',
            'filename': 'picture.png',
        },
    ]
}

headers 是一个HTTPHeaders对象, 使用方法参考:

# 获取元素
print self.request.headers.get('Content-Type')
print self.request.headers['Content-Type']
# 可以直接转字典
print json.dumps(dict(self.request.headers), indent=2)

输出(参考链接):

HTTP status
.set_status()

设置响应HTTP状态码


.send_error() .write_error()

.send_error()用于发送HTTP错误页(状态码). 该操作会调用.clear() .set_status() .write_error()用于清除headers, 设置状态码, 发送错误页. 重写.write_error()可以自定义错误页.

HTTP header
.add_header() .set_header() .set_default_headers()

设置响应HTTP头, 前两者的不同点在于多次设置同一个项时, .add_header()会"叠加"参数, 而.set_header()则以最后一次为准.

# add_header
self.add_header('Foo', 'one')
self.add_header('Foo', 'two')
# set_header
self.set_header('Bar', 'one')
self.set_header('Bar', 'two')

# HTTP头的设置结果
# Foo → one, two
# Bar → two

.set_default_headers()比较特殊, 是一个空方法, 可根据需要重写, 作用是在每次请求初始化RequestHandler时设置默认headers.

.clear_header() .clear()

.clear_header()清除指定的headers, 而.clear()清除.set_default_headers()以外所有的headers设置.

数据流
.write()

将数据写入输出缓冲区. 如果直接传入dict, 那Tornado会自动将其识别为json, 并把Content-Type设置为application/json, 如果你不想要这个Content-Type, 那么在.write()之后, 调用.set_header()重新设置就好了. 需要注意的是, 如果直接传入的是list, 考虑到安全问题(json数组会被认为是一段可执行的JavaScript脚本, 且

你可能感兴趣的:(Tornado应用笔记02-Web框架)