Tornado

发布时间 2023-05-17 16:16:29作者: 叁只小羊

想要用web做一个小链接,大家用上面的信息。

原先用tomcat,但用静态页面比较麻烦,所以找一个简单的框架。

1.1 Tornado

tornado是一个用python编写的,可扩展,无阻塞的web应用程序框架和Web服务器。

在一个进程之间同时处理多个协程,充分利用cpu时间,这需要异步编程。而Tornado就是可以支持异步非堵塞IO模式。

核心原理:协程(使用异步IO)+epoll事件循环

注意:

  • 在代码中不要使用同步IO,会阻塞程序运行。
  • 事件循环模式是单线程的,如果使用了同步IO,所有的消息都会被堵塞。

1.2 安装

pip install tornado

1.3 第一个程序

from tornado import web
from tornado import ioloop


# 控制器
class IndexHandler(web.RequestHandler):
    # get请求
    def get(self):
        self.write("Hello world")


if __name__ == '__main__':
    # 创建app对象,后面列表里设置路由
    # debug=True,修改代码,自动更新,不用重启服务
    app = web.Application([('/', IndexHandler)], debug=True)
    # 监听端口号
    app.listen(8000)
    # 开始事件循环
    ioloop.IOLoop.current().start()

关于工作流程和同步代码:

程序运行: 开始事件循环,监听请求,当得到请求去路由表查询(web.Application),之后执行某个对应的类,如果这个类中有同步代码(比如耗时10秒), 则后继续请求都得等待。因为事件循环是一个单线程的。

1.4 环境参数的传递

一般参数在配置文件中指定,tornado配置环境参数可以用:

  • 命令行
  • 文件设置

1.4.1 命令行参数方式

from tornado import web, ioloop

# define用于定义参数
# options用于访问参数
# parse_command_line用于解析参数
from tornado.options import define, options, parse_command_line

# 定义key接收传递进来的参数
# 参数:name是名称,一个key, default是默认值,help是帮助信息,type是值的类型
define(name="port", default=8000, help="监听端口", type=int)

# 解析命令行传递的参数
parse_command_line()
class IndexHandler(web.RequestHandler):
    # get请求
    async def get(self):
        self.write("Hello world")


if __name__ == '__main__':
    app = web.Application([('/', IndexHandler)], debug=True)
    # 用options读取参数
    # 注意:如果没有parse_command_line()或未指定参数,则默认端口是define中定义的8000
    app.listen(options.port)
    # 开始事件循环
    ioloop.IOLoop.current().start()

调用的时候(注意书写的格式):

python3 main.py --port=7000

1.4.2 配置文件方式

先创建一个配置文件,如:config.conf

# config.conf
# port
port=8000

之后在程序中读取

from tornado import web, ioloop

# parse_config_file用于配置文件解析
from tornado.options import define, options, parse_config_file

# 定义key
define(name="port", default=8000, help="监听端口", type=int)

# 读取并解析,之后更新prot的值
parse_config_file("config.conf")

class IndexHandler(web.RequestHandler):
    # get请求
    async def get(self):
        self.write("Hello world")


if __name__ == '__main__':
    app = web.Application([('/', IndexHandler)], debug=True)
    app.listen(options.port)
    # 开始事件循环
    ioloop.IOLoop.current().start()

1.5 使用URL

from tornado import web, ioloop

class p1(web.RequestHandler):
    async def get(self):
        self.write("p1")

if __name__ == '__main__':
    app = web.Application([
        ('/p1', p1),
    ], debug=True)
    app.listen(7200)
    # 开始事件循环
    ioloop.IOLoop.current().start()

对于: ('/p1', p1) ,进行如下访问:

  • http://localhost:7200/p1 访问正常
  • http://localhost:7200/p1/ 访问出错

这样的URL怎么写才不出错?

('/p1/?', p1)` 

这是一个正则,表示前在的/可有可无

如果要获取更多的内容,可以用这种方法:

from tornado import web, ioloop


class p1(web.RequestHandler):
    async def get(self, username, password):
        self.write(f"p1 {username}, {password}")


if __name__ == '__main__':
    app = web.Application([
    	# (\w+) 用这个正则匹配用户名和密码
        ('/p1/(\w+)/(\w+)/?', p1),
    ], debug=True)
    app.listen(7200)
    # 开始事件循环
    ioloop.IOLoop.current().start()

在访问时:

http://localhost:7200/p1/admin/123456/

此时admin,123456分配传递到username, password参数中。

1.5.1 URL的跳转

从一个URL跳到另一个URL

from tornado import web, ioloop


class Index(web.RequestHandler):
    async def get(self):
        # 跳转到一个网址
        self.redirect("https://www.baidu.com")

if __name__ == '__main__':
    app = web.Application([
        ('/index/?', Index)
    ], debug=True)
    app.listen(7300)
    # 开始事件循环
    ioloop.IOLoop.current().start()

在内部跳转:

from tornado import web, ioloop

class Index(web.RequestHandler):
    async def get(self):
        # 跳到指定的名字的控制器去执行。
        self.redirect(self.reverse_url("default"))

class Default(web.RequestHandler):
    async def get(self):
        self.write("welcome! ")

if __name__ == '__main__':
    app = web.Application([
        ('/index/?', Index),
        # 用下面的方法书写,后面指定一个名字
        web.URLSpec('/default/?', Default, name="default")
    ], debug=True)
    app.listen(7300)
    # 开始事件循环
    ioloop.IOLoop.current().start()

1.6 RequestHandler的使用

在使用的时候,继承:`tornado.web.RequestHandler

  • initialize 初始化
  • prepare 在get,post,etc之前的请求开始时调用
  • on_finish 请求结束后调用,用于清理
  • get_argument 返回具有给定名称的参数的值
  • get_arguments 返回具有给定名称的参数列表
  • get_query_argument 从请求查询字符串中返回具有给定名称的参数值
  • get_query_arguments 返回具有给定名称查询参数的列表
  • get_body_argument 从请求主体返回具有给定名称的参数的值
  • get_body_arguments 返回具有给定名称的主体参数列表
  • request

未完成...