首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Tornado进阶

Tornado进阶

作者头像
星哥玩云
发布2022-09-14 19:06:40
发布2022-09-14 19:06:40
2.1K0
举报
文章被收录于专栏:开源部署开源部署

一、Application

settings

前面的学习中,我们在创建tornado.web.Application的对象时,传入了第一个参数——路由映射列表。实际上Application类的构造函数还接收很多关于tornado web应用的配置参数

参数

debug设置

tornado是否工作在调试模式,默认为False即工作在生产模式。当设置debug=True 后,tornado会工作在调试/开发模式

tornado为方便我们开发而提供了几种特性

  • 自动重启:tornado应用会监控我们的源代码文件,当有改动保存后便会重启程序,这可以减少我们手动重启程序的次数。需要注意的是,一旦我们保存的更改有错误,自动重启会导致程序报错而退出,从而需要我们保存修正错误后手动启动程序。这一特性也可单独通过autoreload=True设置
  • 取消缓存编译的模板:可以单独通过compiled_template_cache=False来设置
  • 取消缓存静态文件hash值:可以单独通过static_hash_cache=False来设置;
  • 提供追踪信息:当RequestHandler或者其子类抛出一个异常而未被捕获后,会生成一个包含追踪信息的页面,可以单独通过serve_traceback=True来设置

使用debug参数的方法

代码语言:javascript
复制
<span class="hljs-keyword">import</span> tornado.web
app = tornado.web.Application([], debug=<span class="hljs-keyword">True</span>)

使用autoreload参数的方法

代码语言:javascript
复制
app = tornado.web.Application([
        (<span class="hljs-string">r"/"</span>, IndexHandler),
    ],autoreload=<span class="hljs-keyword">True</span>)

路由映射

先前我们在构建路由映射列表的时候,使用的是二元元组,如:

代码语言:javascript
复制
[(r"/", IndexHandler),]

对于这个映射列表中的路由,实际上还可以传入多个信息,如:

代码语言:javascript
复制
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> url
[
    (<span class="hljs-string">r"/"</span>, Indexhandler),
    (<span class="hljs-string">r"/cpp/"</span>, ITHandler, {<span class="hljs-string">"subject"</span>:<span class="hljs-string">"c++"</span>}),
    url(<span class="hljs-string">r"/python/"</span>, ITHandler, {<span class="hljs-string">"subject"</span>:<span class="hljs-string">"python"</span>}, name=<span class="hljs-string">"python_url"</span>)
]

url方法:指定URL和处理程序之间的映射。

对于路由中的字典,会传入到对应的RequestHandler的initialize()方法中

代码语言:javascript
复制
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> RequestHandler
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ITHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(self, subject)</span>:</span>
        self.subject = subject

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(self.subject)

对于路由中的name字段,注意此时不能再使用元组,而应使用tornado.web.url来构建。name是给该路由起一个名字,可以通过调用RequestHandler.reverse_url(name)来获取该名子对应的url

代码语言:javascript
复制
<span class="hljs-keyword">import</span> tornado.web
<span class="hljs-keyword">import</span> tornado.ioloop
<span class="hljs-keyword">import</span> tornado.httpserver
<span class="hljs-keyword">import</span> tornado.options
<span class="hljs-keyword">from</span> tornado.options <span class="hljs-keyword">import</span> options, define
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> url, RequestHandler

define(<span class="hljs-string">"port"</span>, default=<span class="hljs-number">8000</span>, type=int, help=<span class="hljs-string">"run server on the given port."</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        python_url = self.reverse_url(<span class="hljs-string">"python_url"</span>)
        self.write(<span class="hljs-string">'&lt;a href="https://www.zutuanxue.com/home/8/%s"&gt;python学科&lt;/a&gt;'</span> %
                   python_url)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ITHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(self, subject)</span>:</span>
        self.subject = subject

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(self.subject)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    tornado.options.parse_command_line()
    app = tornado.web.Application([
            (<span class="hljs-string">r"/"</span>, Indexhandler),
            (<span class="hljs-string">r"/cpp"</span>, ITHandler, {<span class="hljs-string">"subject"</span>:<span class="hljs-string">"c++"</span>}),
            url(<span class="hljs-string">r"/python"</span>, ITHandler, {<span class="hljs-string">"subject"</span>:<span class="hljs-string">"python"</span>}, name=<span class="hljs-string">"python_url"</span>)
        ],
        debug = <span class="hljs-keyword">True</span>)
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

重写 RequestHandler 的方法函数

对于一个请求的处理过程代码调用次序如下

  • 程序为每一个请求创建一个 RequestHandler 对象
  • 程序调用 initialize() 函数,这个函数的参数是 Application 配置中的关键字参数定义。(initialize 方法是 Tornado 1.1 中新添加的,旧版本中你需要重写 __init__ 以达到同样的目的) initialize 方法一般只是把传入的参数存到成员变量中,而不会产生一些输出或者调用像 send_error 之类的方法
  • 程序调用 prepare()。无论使用了哪种 HTTP 方法,prepare 都会被调用到,因此这个方法通常会被定义在一个基类中,然后在子类中重用。prepare可以产生输出信息。如果它调用了finish(或send_error` 等函数),那么整个处理流程就此结束
  • 程序调用某个 HTTP 方法:例如 get()post()put() 等。如果 URL 的正则表达式模式中有分组匹配,那么相关匹配会作为参数传入方法。

重写 initialize() 函数(会在创建RequestHandler对象后调用)

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProfileHandler</span><span class="hljs-params">(tornado.web.RequestHandler)</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(self,database)</span>:</span>
        self.database = database

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"result:"</span> + self.database)

application = tornado.web.Application([
    (<span class="hljs-string">r"/init"</span>, ProfileHandler, dict(database=<span class="hljs-string">"database"</span>))
])

二、请求

下面主要讲解tornado.web.RequestHandler

利用HTTP协议向服务器传参有几种途径

  • 查询字符串(query string),形如key1=value1&key2=value2
  • 请求体(body)中发送的数据,比如表单数据、json、xml
  • 提取uri的特定部分,如/blogs/2019/09/0001,可以在服务器端的路由中用正则表达式截取
  • 在http报文的头(header)中增加自定义字段,如X-XSRFToken=xxx

tornado中提供了以下方法来获取请求的信息

  • 获取查询字符串参数
    • get_query_argument(name, default=_ARG_DEFAULT, strip=True)注意:从请求的查询字符串中返回指定参数name的值,如果出现多个同名参数,则返回最后一个的值 default为设值未传name参数时返回的默认值,如若default也未设置,则会抛出tornado.web.MissingArgumentError异常 strip表示是否过滤掉左右两边的空白字符,默认为过滤
    • get_query_arguments(name, strip=True) 从请求的查询字符串中返回指定参数name的值,注意返回的是list列表(即使对应name参数只有一个值)。若未找到name参数,则返回空列表[] strip同前,不再赘述
  • 获取请求体参数
    • get_body_argument(name, default=_ARG_DEFAULT, strip=True)从请求体中返回指定参数name的值,如果出现多个同名参数,则返回最后一个的值。 default与strip同前,不再赘述
    • get_body_arguments(name, strip=True) 从请求体中返回指定参数name的值,注意返回的是list列表(即使对应name参数只有一个值)。若未找到name参数,则返回空列表[] strip同前,不再赘述 说明:对于请求体中的数据要求为字符串,且格式为表单编码格式(与url中的请求字符串格式相同),即key1=value1&key2=value2,HTTP报文头Header中的"Content-Type"为application/x-www-form-urlencoded 或 multipart/form-data。对于请求体数据为json或xml的,无法通过这两个方法获取。
  • 前两类方法的整合
    • get_argument(name, default=_ARG_DEFAULT, strip=True) 从请求体和查询字符串中返回指定参数name的值,如果出现多个同名参数,则返回最后一个的值 default与strip同前,不再赘述
    • get_arguments(name, strip=True) 从请求体和查询字符串中返回指定参数name的值,注意返回的是list列表(即使对应name参数只有一个值)。若未找到name参数,则返回空列表[] strip同前,不再赘述

    说明:对于请求体中数据的要求同前 这两个方法最常用

使用

代码语言:javascript
复制
<span class="hljs-keyword">import</span> tornado.web
<span class="hljs-keyword">import</span> tornado.ioloop
<span class="hljs-keyword">import</span> tornado.httpserver
<span class="hljs-keyword">import</span> tornado.options
<span class="hljs-keyword">from</span> tornado.options <span class="hljs-keyword">import</span> options, define
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> RequestHandler, MissingArgumentError

define(<span class="hljs-string">"port"</span>, default=<span class="hljs-number">8000</span>, type=int, help=<span class="hljs-string">"run server on the given port."</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self)</span>:</span>
        query_arg = self.get_query_argument(<span class="hljs-string">"a"</span>)
        query_args = self.get_query_arguments(<span class="hljs-string">"a"</span>)
        body_arg = self.get_body_argument(<span class="hljs-string">"a"</span>)
        body_args = self.get_body_arguments(<span class="hljs-string">"a"</span>, strip=<span class="hljs-keyword">False</span>)
        arg = self.get_argument(<span class="hljs-string">"a"</span>)
        args = self.get_arguments(<span class="hljs-string">"a"</span>)

        default_arg = self.get_argument(<span class="hljs-string">"b"</span>, <span class="hljs-string">"itcast"</span>)
        default_args = self.get_arguments(<span class="hljs-string">"b"</span>)

        <span class="hljs-keyword">try</span>:
            missing_arg = self.get_argument(<span class="hljs-string">"c"</span>)
        <span class="hljs-keyword">except</span> MissingArgumentError <span class="hljs-keyword">as</span> e:
            missing_arg = <span class="hljs-string">"We catched the MissingArgumentError!"</span>
            <span class="hljs-keyword">print</span> e
        missing_args = self.get_arguments(<span class="hljs-string">"c"</span>)

        rep = <span class="hljs-string">"query_arg:%s&lt;br/&gt;"</span> % query_arg
        rep += <span class="hljs-string">"query_args:%s&lt;br/&gt;"</span> % query_args 
        rep += <span class="hljs-string">"body_arg:%s&lt;br/&gt;"</span>  % body_arg
        rep += <span class="hljs-string">"body_args:%s&lt;br/&gt;"</span> % body_args
        rep += <span class="hljs-string">"arg:%s&lt;br/&gt;"</span>  % arg
        rep += <span class="hljs-string">"args:%s&lt;br/&gt;"</span> % args 
        rep += <span class="hljs-string">"default_arg:%s&lt;br/&gt;"</span> % default_arg 
        rep += <span class="hljs-string">"default_args:%s&lt;br/&gt;"</span> % default_args 
        rep += <span class="hljs-string">"missing_arg:%s&lt;br/&gt;"</span> % missing_arg
        rep += <span class="hljs-string">"missing_args:%s&lt;br/&gt;"</span> % missing_args

        self.write(rep)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    tornado.options.parse_command_line()
    app = tornado.web.Application([
        (<span class="hljs-string">r"/"</span>, IndexHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

RequestHandler.request属性

说明:RequestHandler.request 对象存储了关于请求的相关信息

格式:self.request.属性名

  • method HTTP的请求方式,如GET或POST
  • host 被请求的主机名
  • uri 请求的完整资源标示,包括路径和查询字符串
  • path 请求的路径部分
  • query 请求的查询字符串部分
  • version 使用的HTTP版本
  • headers 请求的协议头,是类字典型的对象,支持关键字索引的方式获取特定协议头信息,例如:request.headers[“Content-Type”]
  • body 请求体数据
  • remote_ip 客户端的IP地址
  • files 用户上传的文件,为字典类型,型如:{ "form_filename1":[<tornado.httputil.HTTPFile>, <tornado.httputil.HTTPFile>], "form_filename2":[<tornado.httputil.HTTPFile>,], ... }tornado.httputil.HTTPFile是接收到的文件对象 三个属性: filename 文件的实际名字,与form_filename1不同,字典中的键名代表的是表单对应项的名字 body 文件的数据实体 content_type 文件的类型。 这三个对象属性可以像字典一样支持关键字索引,如request.files[“form_filename1”][0][“body”]

文件上传 (模板中讲解)

正则提取uri

说明

tornado中对于路由映射也支持正则提取uri,提取出来的参数会作为RequestHandler中对应请求方式的成员方法参数。若在正则表达式中定义了名字,则参数按名传递;若未定义名字,则参数按顺序传递。提取出来的参数会作为对应请求方式的成员方法的参数

示例

代码语言:javascript
复制
<span class="hljs-keyword">import</span> tornado.web
<span class="hljs-keyword">import</span> tornado.ioloop
<span class="hljs-keyword">import</span> tornado.httpserver
<span class="hljs-keyword">import</span> tornado.options
<span class="hljs-keyword">from</span> tornado.options <span class="hljs-keyword">import</span> options, define
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> RequestHandler

define(<span class="hljs-string">"port"</span>, default=<span class="hljs-number">8000</span>, type=int, help=<span class="hljs-string">"run server on the given port."</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"hello lucky"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubjectCityHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self, subject, city)</span>:</span>
        self.write((<span class="hljs-string">"Subject: %s&lt;br/&gt;City: %s"</span> % (subject, city)))

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubjectDateHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self, date, subject)</span>:</span>
        self.write((<span class="hljs-string">"Date: %s&lt;br/&gt;Subject: %s"</span> % (date, subject)))

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    tornado.options.parse_command_line()
    app = tornado.web.Application([
        (<span class="hljs-string">r"/"</span>, IndexHandler),
        (<span class="hljs-string">r"/sub-city/(.+)/([a-z]+)"</span>, SubjectCityHandler), <span class="hljs-comment"># 无名方式</span>
        (<span class="hljs-string">r"/sub-date/(?P&lt;subject&gt;.+)/(?P&lt;date&gt;\d+)"</span>, SubjectDateHandler), <span class="hljs-comment"># 命名方式</span>
    ])
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
  tornado.ioloop.IOLoop.current().start()

建议:提取多个值时最好用命名方式

三、响应

write(chunk)

将chunk数据写到输出缓冲区

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"hello lucky!"</span>)

多次写入

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"lucky is a good man!"</span>)
        self.write(<span class="hljs-string">"lucky is a good handsome man!"</span>)
        self.write(<span class="hljs-string">"lucky is a lucky man!"</span>)

注意:write方法是写到缓冲区的,我们可以像写文件一样多次使用write方法不断追加响应内容,最终所有写到缓冲区的内容一起作为本次请求的响应输出

写入json数据

json.dumps

代码语言:javascript
复制
<span class="hljs-keyword">import</span> json

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        stu = {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"lucky"</span>,
            <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>,
            <span class="hljs-string">"sex"</span>: <span class="hljs-string">'man'</span>,
        }
        stu_json = json.dumps(stu)
        self.write(stu_json)

注意:实际上,我们可以不用自己手动去做json序列化,当write方法检测到我们传入的chunk参数是字典类型后,会自动帮我们转换为json字符串

write自动转换

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        stu = {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"lucky"</span>,
            <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>,
            <span class="hljs-string">"sex"</span>: <span class="hljs-string">'man'</span>,
        }
        self.write(stu)

区别

  • 对比一下两种方式的响应头header中Content-Type字段,自己手动序列化时为Content-Type:text/html; charset=UTF-8,而采用write方法时为Content-Type:application/json; charset=UTF-8

write方法除了帮我们将字典转换为json字符串之外,还帮我们将Content-Type设置为application/json; charset=UTF-8

关于Content-Type几种值的区别及用法

Content-Type 的值类型:

  • application/json:消息主体是序列化后的 JSON 字符串
  • application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式
  • multipart/form-data: 需要在表单中进行文件上传时,就需要使用该格式。常见的媒体格式是上传文件之时使用的
  • text/plain:数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符

application/json 和 application/x-www-form-urlencoded的区别

  • application/json 作用: 告诉服务器请求的主题内容是json格式的字符串,服务器端会对json字符串进行解析 好处: 前端人员不需要关心数据结构的复杂度,只要是标准的json格式就能提交成功
  • application/x-www-form-urlencoded:是Jquery的Ajax请求默认方式 作用:在请求发送过程中会对数据进行序列化处理,以键值对形式?key1=value1&key2=value2的方式发送到服务器 好处: 所有浏览器都支持

application/x-www-form-urlencoded:信息数据被编码为名称/值对,这是标准且默认的编码格式

  • 当action为get时候,客户端把form数据转换成一个字串append到url后面,用’?'分割
  • 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。(可以取消post请求的预检请求)

总结:

如果响应类型为 application/json 那么服务器会自动解析 那么到前端的时候就不需要再次解析 直接使用就可以 就和Django和flask中的 JsonHttpresponse和jsonify的作用一样

设置响应头 set_header(name, value)

说明:利用set_header(name, value)方法,可以手动设置一个名为name、值为value的响应头header字段

用set_header方法来实现write设置响应头

代码语言:javascript
复制
<span class="hljs-keyword">import</span> json

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        stu = {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"lucky"</span>,
            <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>,
            <span class="hljs-string">"sex"</span>: <span class="hljs-string">'man'</span>,
        }
        stu_json = json.dumps(stu)
        self.write(stu_json)
        self.set_header(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json; charset=UTF-8"</span>)

set_default_headers()

说明:该方法会在进入HTTP处理方法前先被调用,可以重写此方法来预先设置默认的headers

注意:在HTTP处理方法中使用set_header()方法会覆盖掉在set_default_headers()方法中设置的同名header

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_default_headers</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"执行了set_default_headers()"</span>)
        <span class="hljs-comment"># 设置get与post方式的默认响应体格式为json</span>
        self.set_header(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json; charset=UTF-8"</span>)
        <span class="hljs-comment"># 设置一个名为lucky、值为is  a good man的header</span>
        self.set_header(<span class="hljs-string">"lucky"</span>, <span class="hljs-string">"is  a good man"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"执行了get()"</span>)
        stu = {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"lucky"</span>,
            <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>,
            <span class="hljs-string">"sex"</span>: <span class="hljs-string">'man'</span>,
        }
        stu_json = json.dumps(stu)
        self.write(stu_json)
        self.set_header(<span class="hljs-string">"lucky"</span>, <span class="hljs-string">"is  a handsome man"</span>) <span class="hljs-comment"># 注意此处重写了header中的lucky字段</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"执行了post()"</span>)
        stu = {
            <span class="hljs-string">"name"</span>: <span class="hljs-string">"lucky"</span>,
            <span class="hljs-string">"age"</span>: <span class="hljs-number">18</span>,
            <span class="hljs-string">"sex"</span>: <span class="hljs-string">'man'</span>,
        }
        stu_json = json.dumps(stu)
        self.write(stu_json)

终端中打印出的执行

get请求方式的响应header

post请求方式的响应header

set_status(status_code, reason=None)

说明:为响应设置状态码

参数说明

  • status_code int类型,状态码,若reason为None,则状态码必须为下表中的
  • reason string类型,描述状态码的词组,若为None,则会被自动填充标准HTTP状态码

HTTP协议常用标准状态码含义

状态码

含义

备注

200

请求已完成

2XX状态码均为正常状态码返回。

300

多种选择

服务器根据请求可执行多种操作。服务器可根据请求者 (User agent) 来选择一项操作,或提供操作列表供请求者选择。

301

永久移动

请求的网页已被永久移动到新位置。服务器返回此响应(作为对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码通知 Googlebot 某个网页或网站已被永久移动到新位置。

302

临时移动

服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置。

303

查看其他位置

当请求者应对不同的位置进行单独的 GET 请求以检索响应时,服务器会返回此代码。对于除 HEAD 请求之外的所有请求,服务器会自动转到其他位置。

304

未修改

自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容。

305

使用代理

请求者只能使用代理访问请求的网页。如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。

400

错误请求

服务器不理解请求的语法。

401

未授权

请求要求进行身份验证。登录后,服务器可能会对页面返回此响应。

403

已禁止

服务器拒绝请求。

404

未找到

服务器找不到请求的网页。例如,如果请求是针对服务器上不存在的网页进行的,那么,服务器通常会返回此代码。

405

方法禁用

禁用请求中所指定的方法。

406

不接受

无法使用请求的内容特性来响应请求的网页。

407

需要代理授权

此状态代码与401(未授权)类似,但却指定了请求者应当使用代理进行授权。如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。

408

请求超时

服务器等候请求时超时。

409

冲突

服务器在完成请求时发生冲突。服务器的响应必须包含有关响应中所发生的冲突的信息。服务器在响应与前一个请求相冲突的PUT请求时可能会返回此代码,同时会提供两个请求的差异列表。

411

需要有效长度

服务器不会接受包含无效内容长度标头字段的请求。

412

未满足前提条件

服务器未满足请求者在请求中设置的其中一个前提条件。

413

请求实体过大

服务器无法处理请求,因为请求实体过大,已超出服务器的处理能力。

414

请求的URI过长

请求的URI(通常为网址)过长,服务器无法进行处理。

415

不支持的媒体类型

请求的格式不受请求页面的支持。

416

请求范围不符合要求

如果请求是针对网页的无效范围进行的,那么,服务器会返回此状态代码。

417

未满足期望值

服务器未满足期望请求标头字段的要求。

499

客户端断开连接

因服务端处理时间过长,客户端关闭了连接。

500

服务器内部错误

服务器遇到错误,无法完成请求。

501

尚未实施

服务器不具备完成请求的功能。例如,当服务器无法识别请求方法时,服务器可能会返回此代码。

502

错误网关

服务器作为网关或代理,从上游服务器收到了无效的响应。

503

服务不可用

目前无法使用服务器(由于超载或进行停机维护)。通常,这只是一种暂时的状态。

504

网关超时

服务器作为网关或代理,未及时从上游服务器接收请求。

505

HTTP版本不受支持

服务器不支持请求中所使用的HTTP协议版本。

示例

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Err404Handler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-string">"""对应/err/404"""</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"hello Lucky"</span>)
        self.set_status(<span class="hljs-number">404</span>) <span class="hljs-comment"># 标准状态码,不用设置reason</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Err210Handler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-string">"""对应/err/210"""</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"hello lucky"</span>)
        self.set_status(<span class="hljs-number">210</span>, <span class="hljs-string">"lucky error"</span>) <span class="hljs-comment"># 非标准状态码,设置了reason</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Err211Handler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-string">"""对应/err/211"""</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"hello lucky"</span>)
        self.set_status(<span class="hljs-number">211</span>) <span class="hljs-comment"># 非标准状态码,未设置reason,错误</span>

请求结果

redirect(url)

说明:重定向 服务器直接跳转

示例

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-string">"""对应/"""</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"主页"</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-string">"""对应/login"""</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">'&lt;form method="post"&gt;&lt;input type="submit" value="登陆"&gt;&lt;/form&gt;'</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self)</span>:</span>
        self.redirect(<span class="hljs-string">"/"</span>)  <span class="hljs-comment"># 重定向到首页</span>

send_error(status_code=500, **kwargs)

说明:抛出HTTP错误状态码status_code,默认为500,kwargs为可变命名参数。使用send_error抛出错误后tornado会调用write_error()方法进行处理,并返回给浏览器处理后的错误页面

示例

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"主页"</span>)
        self.send_error(<span class="hljs-number">404</span>, content=<span class="hljs-string">"出现404错误"</span>)

注意:默认的write_error()方法不会处理send_error抛出的kwargs参数,即上面的代码中content="出现404错误"是没有意义的

继续使用write方法

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"主页"</span>)
        self.send_error(<span class="hljs-number">404</span>, content=<span class="hljs-string">"出现404错误"</span>)
        self.write(<span class="hljs-string">"结束"</span>) <span class="hljs-comment"># 我们在send_error再次向输出缓冲区写内容</span>

注意:使用send_error()方法后就不会再向输出缓冲区写内容了

write_error(status_code, **kwargs)

说明:用来处理send_error抛出的错误信息并返回给浏览器错误信息页面。可以重写此方法来定制自己的错误显示页面

示例

代码语言:javascript
复制
<span class="hljs-keyword">import</span> tornado.web
<span class="hljs-keyword">import</span> tornado.ioloop
<span class="hljs-keyword">from</span> tornado.web <span class="hljs-keyword">import</span> RequestHandler

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        self.write(<span class="hljs-string">"主页"</span>)
        self.send_error(<span class="hljs-number">404</span>, content=<span class="hljs-string">"出现404错误"</span>)
        self.write(<span class="hljs-string">"结束"</span>)  <span class="hljs-comment"># 我们在send_error再次向输出缓冲区写内容</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">write_error</span><span class="hljs-params">(self, status_code, **kwargs)</span>:</span>
        self.write(<span class="hljs-string">"&lt;h1&gt;出错了,程序员GG正在赶过来!&lt;/h1&gt;"</span>)
        self.write(<span class="hljs-string">"&lt;p&gt;错误名:%s&lt;/p&gt;"</span> % kwargs[<span class="hljs-string">"title"</span>])
        self.write(<span class="hljs-string">"&lt;p&gt;错误详情:%s&lt;/p&gt;"</span> % kwargs[<span class="hljs-string">"content"</span>])

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app = tornado.web.Application([
        (<span class="hljs-string">r"/"</span>, IndexHandler),
    ])
    app.listen(<span class="hljs-number">8000</span>)
    tornado.ioloop.IOLoop.current().start()

结果

四、接口与调用顺序

initialize()

说明:对应每个请求的处理类Handler在构造一个实例后首先执行initialize()方法

在讲输入时说过,路由映射中的第三个字典型参数会作为该方法的命名参数传递

如:

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProfileHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(self, database)</span>:</span>
        self.database = database

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        ...
app = Application([
      (<span class="hljs-string">r'/user/(.*)'</span>, ProfileHandler, dict(database=database)),
    ])

注意:此方法通常用来初始化参数(对象属性),很少使用

prepare()

说明:预处理,即在执行对应请求方式的HTTP方法(如get、post等)前先执行

注意:不论以何种HTTP方式请求,都会执行prepare()方法

以预处理请求体中的json数据为例:

代码语言:javascript
复制
<span class="hljs-keyword">import</span> json

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">prepare</span><span class="hljs-params">(self)</span>:</span>
        <span class="hljs-keyword">if</span> self.request.headers.get(<span class="hljs-string">"Content-Type"</span>).startswith(<span class="hljs-string">"application/json"</span>):
            self.json_dict = json.loads(self.request.body)
        <span class="hljs-keyword">else</span>:
            self.json_dict = <span class="hljs-keyword">None</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self)</span>:</span>
        <span class="hljs-keyword">if</span> self.json_dict:
            <span class="hljs-keyword">for</span> key, value <span class="hljs-keyword">in</span> self.json_dict.items():
                self.write(<span class="hljs-string">"&lt;h3&gt;%s&lt;/h3&gt;&lt;p&gt;%s&lt;/p&gt;"</span> % (key, value))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">put</span><span class="hljs-params">(self)</span>:</span>
        <span class="hljs-keyword">if</span> self.json_dict:
            <span class="hljs-keyword">for</span> key, value <span class="hljs-keyword">in</span> self.json_dict.items():
                self.write(<span class="hljs-string">"&lt;h3&gt;%s&lt;/h3&gt;&lt;p&gt;%s&lt;/p&gt;"</span> % (key, value))

用post方式发送json数据时

代码语言:javascript
复制
用put方式发送json数据时
  • HTTP方法

方法

描述

get

请求指定的页面信息,并返回实体主体。

head

类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头

post

向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。

delete

请求服务器删除指定的内容。

patch

请求修改局部数据。

put

从客户端向服务器传送的数据取代指定的文档的内容。

options

返回给定URL支持的所有HTTP方法。

on_finish()

在请求处理结束后调用,即在调用HTTP方法后调用。通常该方法用来进行资源清理释放或处理日志等

注意:请尽量不要在此方法中进行响应输出

set_default_headers()

write_error()

调用顺序

示例

代码语言:javascript
复制
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexHandler</span><span class="hljs-params">(RequestHandler)</span>:</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了initialize()"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">prepare</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了prepare()"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_default_headers</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了set_default_headers()"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">write_error</span><span class="hljs-params">(self, status_code, **kwargs)</span>:</span>
        print(<span class="hljs-string">"调用了write_error()"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了get()"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了post()"</span>)
        self.send_error(<span class="hljs-number">200</span>)  <span class="hljs-comment"># 注意此出抛出了错误</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">on_finish</span><span class="hljs-params">(self)</span>:</span>
        print(<span class="hljs-string">"调用了on_finish()"</span>)

在正常情况未抛出错误时,调用顺序为:

  • set_defautl_headers()
  • initialize()
  • prepare()
  • HTTP方法
  • on_finish()

在有错误抛出时,调用顺序为:

  • set_default_headers()
  • initialize()
  • prepare()
  • HTTP方法
  • set_default_headers()
  • write_error()
  • on_finish()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Application
  • 二、请求
  • 三、响应
  • 四、接口与调用顺序
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档