返回顶部

02 | tornado的web基础

tornado之helloworld

一个简单的tornado web应用程序我们要继承tornado web模块中的 RequestHandler ,内部重构请求方法。

然后实例化应用对象,添加映射关系,监听端口,开启时间循环

from tornado import web
import tornado

class MainHandler(web.RequestHandler):
    # 当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    # 下面的get方法,响应http请求中的get请求,请求类型与对应的方法如下:
    #  "GET":get(), "HEAD":head(), "POST":post(), "DELETE":delete(), "PATCH":patch(), "PUT":put(),"OPTIONS":options()
    async def get(self, *args, **kwargs):
        self.write("hello world")

# 二、程序运行入口
if __name__ == "__main__":
    # 1、实例化,application对象
    app = web.Application([
            ("/", MainHandler),       # 配置路由  http://localhost:8888/这个url交给MainHandler处理
        ],
        debug=True                    # 开启调试模式,与flask、Django类似,可以自动重启,打印错误栈
    )
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

 开启了调试模式 debug = true后,修改代码python会开启一个线程在后台运行,可以通过资源管理器杀死这个线程

访问

http://127.0.0.1:8888/ 

返回结果如下

tornado中为什么不能写同步的方法

如下示例代码:

import time

from tornado import web
import tornado
web.URLSpec

class MainHandler(web.RequestHandler):
    async def get(self, *args, **kwargs):
        time.sleep(5)
        self.write("hello world")

class MainHandler2(web.RequestHandler):
    async def get(self, *args, **kwargs):
        self.write("hello world2")

if __name__ == "__main__":
    app = web.Application([
        ("/", MainHandler),
        ("/2/", MainHandler2)
    ], debug=True)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

 

同时访问以下两个url

http://127.0.0.1:8888/

http://127.0.0.1:8888/2/

返回结果如下

当我们先访问http://localhost:8888/ 然后立即 http://localhost:8888/2/,由于tornado的处理http请求是一种单线程的模式,http://localhost:8888/这个请求,如果在请求处理函数中使用同步IO(time.sleep(5)就属于同步

IO)它会阻塞其他的请求处理,直到该请求执行完毕返回”hello world“,然后http://localhost:8888/2/的处理函数才会执行并返回hello world2。

所以通过上述实例,我们一定要注意,千万不要在tornado中使用同步IO

tornado中url的映射配置

 url 命名,直接使用tornado.web中的URLSpec进行实例化,传入name为url命名

 tornado.web.URLSpec("/", MainHandler, name="index"),

  

通过 url 的名字进行重定向

self.redirect(self.reverse_url(url名字, "传递的参数"))

  

 给handler 传入初始值

 把字典中的name的值people传入给handler

people_db = {
    "name": "people"
}

urls = [
    tornado.web.URLSpec("/people/(\d+)/?", PeopleIdHandler, people_db, name="people_id"),
]

  

通过 initialize 方法接受初始值

class PeopleIdHandler(web.RequestHandler):
    def initialize(self, name):
        self.db_name = name

    async def get(self, id, *args, **kwargs):
        print(self.db_name)
        self.redirect(self.reverse_url("people_name", "zhangbiao"))

  

 完整实例

import time

from tornado import web
import tornado

class MainHandler(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        self.write("hello world")

class PeopleIdHandler(web.RequestHandler):
    def initialize(self, name):
        self.db_name = name

    async def get(self, id, *args, **kwargs):
        print(self.db_name)
        self.redirect(self.reverse_url("people_name", "zhangbiao"))

class PeopleNameHandler(web.RequestHandler):
    async def get(self, name, *args, **kwargs):
        self.write("用户姓名:{}".format(name))

class PeopleInfoHandler(web.RequestHandler):
    async def get(self, name, age, gender, *args, **kwargs):
        self.write("用户姓名:{},用户年龄:{},用户性别:{},".format(name, age, gender))

people_db = {
    "name":"people"
}
from tornado.web import url
#配置如/people/1/
urls = [
    tornado.web.URLSpec("/", MainHandler, name="index"),
    tornado.web.URLSpec("/people/(\d+)/?", PeopleIdHandler, people_db, name="people_id"),
    tornado.web.URLSpec("/people/(\w+)/?", PeopleNameHandler, name="people_name"), #配置如/people/zhangbiao/
    tornado.web.URLSpec("/people/(?P<name>\w+)/(?P<age>\d+)/(?P<gender>\w+)/?", PeopleInfoHandler, name="people_info"), #配置如/people/name/age/gender/
]

if __name__ == "__main__":
    app = web.Application(urls, debug=True)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

define、options、parse_comand_line,parse_config_file

常量配置通过define()函数来定义,然后,通过options来获取

define: 定义一些可以在命令行中传递的参数以及类型

options:options是一个类,全局只有一个options

options.parse_comand_line:从命行行中读取参数

options.parse_config_file:从配置文件中读取参数

 

创建配置文件conf.cfg

port=8002

启动程序代码如下

from tornado import web
import tornado
from tornado.options import define, options, parse_command_line

#define, 定义一些可以在命令行中传递的参数以及类型
define('port', default=8008, help="run on the given port", type=int)
define('debug', default=True, help="set tornado debug mode", type=bool)

# options.parse_command_line()从配置文件中读取
options.parse_config_file("conf.cfg")

#options是一个类,全局只有一个options

class MainHandler(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        self.write("hello world")

class MainHandler2(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        self.write("hello world2")

if __name__ == "__main__":
    app = web.Application([
        ("/", MainHandler),
        ("/2/", MainHandler2)
    ], debug=options.debug)
    app.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

在终端输入以下命令启动

python options_test.py --port=8002

返回结果如下

RequestHandler常用方法和子类

initialize 方法  用于初始化handler类的过程

from tornado.web import RequestHandler

class MainHandler(RequestHandler):
    #入口
    def initialize(self, db):
        #用于初始化handler类的过程
        self.db = db
   def get(self, *args, **kwargs):
        pass
people_db = {
    "name": "people"
}

import tornado
urls = [
    tornado.web.URLSpec("/", MainHandler,people_db, name="index"),
]

 

 

prepare 方法 用于真正调用请求处理之前的初始化方法

from tornado.web import RequestHandler

class MainHandler(RequestHandler):
    #入口
    def prepare(self):
        #prepare方法用于真正调用请求处理之前的初始化方法
        #1. 打印日志, 打开文件
        pass

   def get(self, *args, **kwargs):
        pass
people_db = {
    "name": "people"
}

import tornado
urls = [
    tornado.web.URLSpec("/", MainHandler,people_db, name="index"),
]

 

on_finish 方法 请求结束执行的操作

from tornado.web import RequestHandler

class MainHandler(RequestHandler):
    #入口
    def initialize(self, db):
        #用于初始化handler类的过程
        self.db = db

    def prepare(self):
        #prepare方法用于真正调用请求处理之前的初始化方法
        #1. 打印日志, 打开文件
        pass

    def on_finish(self):
        #关闭句柄, 清理内存
        pass
people_db = {
    "name": "people"
}

import tornado
urls = [
    tornado.web.URLSpec("/", MainHandler,people_db, name="index"),
]

write_error方法

重写自定义错误页面的实现。

如果error是由没有捕获的异常(包括HTTPError)引起的,通过kwargs[|”exc_info”]能获取exc_info元组。实现代码如下:

import traceback

from tornado.web import RequestHandler

class MainHandler(RequestHandler):
    #入口
    def initialize(self, db):
        #用于初始化handler类的过程
        self.db = db

    def prepare(self):
        #prepare方法用于真正调用请求处理之前的初始化方法
        #1. 打印日志, 打开文件
        pass

    def on_finish(self):
        #关闭句柄, 清理内存
        pass


    #http方法
    def get(self, *args, **kwargs):
       pass

    def write_error(self, status_code, **kwargs):
        self.write("oh,my god!出错啦!!!!请联系系统管理员。\n")
        self.write("呵呵,也没关系,我已经讲错误信息记录在日志中去了,系统管理员会看到的。\r\n")
        if "exc_info" in kwargs:
            self.write("错误信息为:\r\n")
            for line in traceback.format_exception(*kwargs["exc_info"]):
                self.write(line)
        self.finish()

people_db = {
    "name": "people"
}

import tornado
urls = [
    tornado.web.URLSpec("/", MainHandler,people_db, name="index"),
]

if __name__ == "__main__":
    from tornado import web
    app = web.Application(urls, debug=True)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

 

获取前端传递的参数

 1、 get_argument、get_arguments方法 在get 和 post 方法中都可以使用

 get_argument获得单个值,而get_arguments是针对参数存在多个值得情况下使用,返回多个值的列表。

 

request.arguments 获取所有的参数包括 url中的参数和表单中传递的

传入参数如下

后台打印结果如下

获取json数据

    def post(self, *args, **kwargs):
        param = self.request.body.decode("utf8")
        data1 = json.loads(param)
        print(data1)  

传入数据如下

后台打印结果如下

 

self.finish 方法 关闭长连接,还可以写回数据

    def post(self, *args, **kwargs):

        self.finish({
            "name":"bobby"
        })
     self.wirte("haha") # 关闭了长连接,下面的不会执行

set_status(code)  方法 设置状态码

    def post(self, *args, **kwargs):

        try:
            data1 = self.get_body_argument("name")
   except Exception as e:
            self.set_status(500)

        self.finish({
            "name":"bobby"
        })

 

RequestHandler 子类用法:RedirectHandler、StaticFileHandler

RedirectHandler 和 self.redirect的区别

  self.redirect 是临时重定向,主要用于业务逻辑的

  RedirectHandler  是永久性的重定向

StaticFileHandler 静态文件处理器,指定静态资源的目录

 

简单用法

在static/test/test.jpg(放入了一张图片)

from tornado.web import StaticFileHandler, RedirectHandler

#1. RedirectHandler
#1. 301是永久重定向, 302是临时重定向,获取用户个人信息, http://www.baidu.com https

#StaticFileHandler
import time

from tornado import web
import tornado

class MainHandler(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        time.sleep(5)
        self.write("hello world")

class MainHandler2(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        self.write("hello world2")

settings = {
    "static_path":"D:/BaiduYunDownload/971、Tornado从入门到进阶/资料/tornado-resources-master/tornado-resources/tornado_overview/chapter02/static",
    "static_url_prefix":"/static2/"
}

if __name__ == "__main__":
    app = web.Application([
        ("/", MainHandler),
        ("/2/", RedirectHandler, {"url":"/"}), #  永久重定向
        ("/static3/(.*)", StaticFileHandler, {"path": "D:/tornado_overview/chapter02/static"}) # 指定静态文件路径
    ], debug=True, **settings)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

访问

http://127.0.0.1:8888/static3/test/test.jpg

返回结果

 tornado的template

定义模板地址

首先我们需要定义一下模板所在地址,让tornado知道去哪里找模板,一般我们把地址写在入口文件中。下列代码static_path的值就是模板的地址

settings = {
    "static_path":"C:/projects/tornado_overview/chapter02/static",
    "static_url_prefix":"/static2/",
    "template_path": "templates"
}

if __name__ == "__main__":
    app = web.Application([
        ("/", MainHandler2)
    ], debug=True, **settings)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

传递参数到模板中

当我们在handler处理好数据后,就可以把数据传递到相应的模板中去。

from tornado.web import StaticFileHandler, RedirectHandler

from tornado import web
import tornado
from tornado.web import template


class MainHandler2(web.RequestHandler):
    #当客户端发起不同的http方法的时候, 只需要重载handler中的对应的方法即可
    async def get(self, *args, **kwargs):
        word = "你好"
        self.render("hello.html", word=word)
settings = {
    "static_path":"C:/projects/tornado_overview/chapter02/static",
    "static_url_prefix":"/static2/",
    "template_path": "templates"
}

if __name__ == "__main__":
    app = web.Application([
        ("/", MainHandler2)
    ], debug=True, **settings)
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

templates/hello.html

<h1>{{ word }}</h1>

访问结果如下

填充及控制语句

在模板文件中填充变量,可以使用下列方式获取值:  

{{ quantity }}
{{ com(1) }}

同时tornado还支持一些简单的控制语句:  

{%if 或者 for %}
... 这里是各种表达式
{%end%}

Tornado在所有模板中默认提供了一些便利的函数。它们包括:

  • escape(s):替换字符串s中的&、<、>为他们对应的HTML字符。
  • url_escape(s):使用urllib.quote_plus替换字符串s中的字符为URL编码形式。
  • json_encode(val):将val编码成JSON格式。(在系统底层,这是一个对json库的dumps函数的调用。查阅相关的文档以获得更多关于该函数接收和返回参数的信息。)
  • squeeze(s):过滤字符串s,把连续的多个空白字符替换成一个空格。

其他

{%set str='xxxx'%}
使用:{{str}

模板转义:转义是为了防止你的访客进行恶意攻击的,但当你不希望转移时,可以使用raw来阻止对变量转义。  

{% raw mail %}

  

 tornado的settings

推荐参考官方文档  

 

posted @ 2018-12-26 23:57  Crazymagic  阅读(414)  评论(0编辑  收藏  举报