tornado入门必看2

请求与响应

请求

tornado.httputil.HTTPServerRequest

	from tornado import ioloop
	from tornado import web
	from tornado import autoreload
	
	from tornado.options import define,options,parse_command_line
	
	settings = {
	    'debug' : True,
	}
	
	define("port", default=8888, type=int,help="设置监听端口号,默认为8888")
	class Home(web.RequestHandler):
	    def get(self):
	        print(self.request) # 请求处理对象
	        # HTTPServerRequest(protocol='http', host='127.0.0.1:8888', method='GET', uri='/?name=xiaoming', version='HTTP/1.1', remote_ip='127.0.0.1')
	        # print(self.request.protocol) # 协议
	        # print(self.request.method) # Http请求方法
	        # print(self.request.uri)    # uri地址
	        # print(self.request.full_url())    # 完整url地址
	        # print(self.request.version) # HTTP协议版本
	        # print(self.request.headers) # 请求头 HTTPHeaders
	        # print(self.request.body) # 请求体[原始数据]
	        # print(self.request.host) # 地址端口
	        # print(self.request.files) # 上传文件
	        # print(self.request.cookies) # cookie信息
	        # print(self.request.remote_ip) # 客户端IP地址
	        print(self.request.query_arguments) # 地址参数列表
	        print(self.request.body_arguments) # 请求体参数列表
	        print(self.request.request_time()) # 请求处理时间
	        self.write("hello world")
	
	# 设置路由列表
	urls = [
	    (r"/", Home),
	]
	
	if __name__ == "__main__":
	    # 创建应用实例对象
	    parse_command_line()
	    app = web.Application(urls,**settings)
	    # 设置监听的端口和地址
	    app.listen(options.port)
	    # ioloop,全局的tornado事件循环,是服务器的引擎核心,start表示创建IO事件循环
	    ioloop.IOLoop.current().start()

## 接收查询字符串

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

settings = {
    'debug' : True,
}

define("port", default=8888, type=int,help="设置监听端口号,默认为8888")
class Home(web.RequestHandler):
    def get(self):
        # print(self.request.arguments["name"][0].decode())
        # name = self.get_argument("name") # self.get_query_argument("name")
        # print(name) # xiaoming
        names = self.get_arguments("name") # # self.get_query_arguments("name")
        print(names) # ['xiaoming', '123']
        # self.write 响应数据
        # self.write("hello!")
        self.write("hello world")

# 设置路由列表
urls = [
    (r"/", Home),
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls,**settings)
    # 设置监听的端口和地址
    app.listen(options.port)
    # ioloop,全局的tornado事件循环,是服务器的引擎核心,start表示创建IO事件循环
    ioloop.IOLoop.current().start()

接收请求体

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

settings = {
    'debug' : True,
}

define("port", default=8888, type=int,help="设置监听端口号,默认为8888")
class Home(web.RequestHandler):
    def get(self):
        # print(self.request.arguments["name"][0].decode())
        # name = self.get_argument("name") # self.get_query_argument("name")
        # print(name) # xiaoming
        names = self.get_arguments("name") # # self.get_query_arguments("name")
        print(names) # ['xiaoming', '123']
        self.write("hello!get")

    def post(self):
        print(self.request.arguments) # {'name': [b'xiaoming', b'xiaohong']}
        print(self.request.body_arguments) # {'name': [b'xiaohong']}
        print(self.get_argument("name")) # xiaohong
        print(self.get_body_argument("name")) # xiaohong
        print(self.get_arguments("name")) # ['xiaoming', 'xiaohong']
        print(self.get_body_arguments("name")) # ['xiaohong']
        self.write("hello!post")
        
# 设置路由列表
urls = [
    (r"/", Home),
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls,**settings)
    # 设置监听的端口和地址
    app.listen(options.port)
    # ioloop,全局的tornado事件循环,是服务器的引擎核心,start表示创建IO事件循环
    ioloop.IOLoop.current().start()

接收路由参数

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

settings = {
    'debug' : True,
}

define("port", default=8888, type=int,help="设置监听端口号,默认为8888")

class Home(web.RequestHandler):
    def get(self,name):
        print(name)
        self.write("home!get")

class Index(web.RequestHandler):
    def get(self,name):
        print(name)
        self.write("index!get")

# 路由列表
urls = [
    (r"/home/(.+)", Home), # 不绑定传参
    (r"/index/(?P<name>.+)", Index), # 绑定传参
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls,**settings)
    # 设置监听的端口和地址
    app.listen(options.port)
    # ioloop,全局的tornado事件循环,是服务器的引擎核心,start表示创建IO事件循环
    ioloop.IOLoop.current().start()

响应

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

settings = {
    'debug': True,
}

define("port", default=8888, type=int, help="设置监听端口号,默认为8888")

from datetime import datetime
class Home(web.RequestHandler):
    def set_default_headers(self):
        self.set_header("time", int(datetime.now().timestamp()))

    def get(self):
        # self.write("<h1>hello</h1>") # 响应html文本信息
        self.write({"message":"hello get"}) # 响应json数据
        self.set_header("Content-Type","text/json; charset=gbk")
        self.add_header("Company","OldboyEdu") # 自定义响应头
        self.set_cookie("name","xiaohui") # 设置cookie

    def post(self):
        self.write({"message": "hello post"})  # 响应json数据

    def put(self):
        self.clear_header("time")
        # self.set_status(404,"Not Found")
        # self.send_error(500,reason="服务器炸了!")
        self.send_error(404, msg="服务器炸了!", info="快报警")

    def write_error(self, status_code, **kwargs):
        self.write("<h1>完蛋啦...</h1>")
        self.write("<p>错误信息:%s</p>" % kwargs["msg"])
        self.write("<p>错误描述:%s</p>" % kwargs["info"])

    def patch(self):
        # 页面跳转
        self.redirect("http://www.baidu.com")

# 设置路由列表
urls = [
    (r"/", Home),
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls, **settings)
    # 设置监听的端口和地址
    app.listen(options.port)
    # ioloop,全局的tornado事件循环,是服务器的引擎核心,start表示创建IO事件循环
    ioloop.IOLoop.current().start()

Cookie基本使用

设置cookie self.set_cookie(name, value)

获取cookie self.get_cookie(name)

from tornado import web
from tornado import ioloop
settings = {
    "debug": True,
}

from datetime import datetime
class Home(web.RequestHandler):
    def get(self):
        # 设置cookie
        self.set_cookie("uname","xiaoming",expires=int(datetime.now().timestamp())+10)
        self.write("set cookie")

class Index(web.RequestHandler):
    def get(self):
        # 获取cookie
        uname = self.get_cookie("uname","")
        self.write("uname=%s" % uname)

urls = [
    (r"/cookie/set", Home),
    (r"/cookie/get", Index),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()

加密使用

设置cookie self.set_secure_cookie(name,value)

获取cookie self.get_secure_cookie(name)

删除cookie self.clear_cookie(name)

清空cookie self.clear_all_cookie()

from tornado import web
from tornado import ioloop
settings = {
    "debug": True,
    # import base64, uuid
    # base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
    "cookie_secret": "WO+JNAJ3QZyOe4SMVXZpXAt3uG9hoU0UokoCBeYn1Y4="
}

from datetime import datetime
class Home(web.RequestHandler):
    def get(self):
        self.set_secure_cookie("name","xiaoming",expires=int(datetime.now().timestamp())+30)
        self.set_secure_cookie("age","16",expires=int(datetime.now().timestamp())+30)
        self.write("set cookie")

class Index(web.RequestHandler):
    def get(self):
        # 获取cookie[加密]
        age = self.get_secure_cookie("age")
        name = self.get_secure_cookie("name")
        if age is not None:
            age  = age.decode()
        if name is not None:
            name = name.decode()
        self.write("age=%s,name=%s" % (age,name))

class Page(web.RequestHandler):
    def get(self):
        """删除cookie"""
        # self.clear_cookie("age") # 删除指定名称的cookie[不管是否有加密]
        self.clear_all_cookies() # 删除所有cookie[慎用]
        self.write("del cookie")

urls = [
    (r"/cookie/set", Home),
    (r"/cookie/get", Index),
    (r"/cookie/del", Page),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()

静态文件

from tornado import web
from tornado import ioloop
import os
settings = {
    'debug': True,
    # 静态文件保存路径
    "static_path": os.path.join(os.path.dirname(__file__), 'static'),
    # 静态文件url地址前缀
    "static_url_prefix":"/static/", # 必须前后有斜杠
    # 提供静态文件访问支持的视图类
    "static_handler_class": web.StaticFileHandler,
}

class Home(web.RequestHandler):
    def get(self):
        # 项目中使用join拼凑路径时,必须注意第二个参数,必能以斜杠开头,会出现路径穿越(路径穿透)问题
        path = os.path.join(os.path.dirname(__file__),"/static")
        self.write("path=%s" % path)

urls = [
    (r"/", Home),
    # 上面settings中关于静态文件的配置,主要是提供给Application应用对象进行初始化生成下面路由时候使用到的。
    # (r"/static/(.*)", web.StaticFileHandler, {"path": os.path.join(os.path.dirname(__file__), 'static')}),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()

页面响应

加载template文件

from tornado import web
from tornado import ioloop
import os
settings = {
    'debug': True,
    "template_path": os.path.join(os.path.dirname(__file__), 'templates'),
}

class Home(web.RequestHandler):
    def get(self):
        self.render("index.html",data={"message":"hello world"})

urls = [
    (r"/", Home),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>{
   
   {data["message"]}}</p>

</body>
</html>

路由进阶

from tornado import web
from tornado import ioloop
settings = {
    'debug': True,
}

class Home(web.RequestHandler):
    def initialize(self,company)-> str:
        # initialize 初始化方法[钩子方法]
        self.company = company

    def get(self):
        print(self.company)
        print("uri路径:%s" % self.reverse_url("home") ) # 对路由别名进行 反解析
        self.write("hello,get")
    def post(self):
        print(self.company)

from tornado.web import url
urls = [
    # (r"/", Home), # 这个格式的路由其实是简写模式, 在tornaodo.web中内部中最终由 _ApplicationRouter 的 Rule来进行封装和匹配路由和视图的关系
    # url(pattern=路由uri地址, handler=视图类,kwargs=提供给视图类的公共参数,name="路由别名,用于反解析"),
    url(pattern=r"/abc", handler=Home,kwargs={"company":"OldBoyEdu"},name="home"),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()

视图进阶

在tornado提供的视图类中,我们除了可以编写客户端http请求对应名称的视图方法和初始化方法initialize以外,还提供了一个预处理方法prepare和on_finish,prepare方法会在http请求方法执行之前先执行,on_finish会在http响应完成时进行。

from tornado import ioloop
from tornado import web
from tornado.httpserver import HTTPServer
from tornado.options import define, options, parse_command_line
from tornado.web import url
settings = {
    'debug': True,
}

define("port", default=8888, type=int, help="设置监听端口号,默认为8888")

class Home(web.RequestHandler):
    def initialize(self):
        print("initialize执行了")

    def prepare(self):
        print("prepare执行了")


    def set_default_headers(self):
        print("set_default_headers执行了")

    def get(self):
        self.write("hello,get")
        print("视图http方法执行了")
        # self.send_error(200,msg="注意:丢炸弹了")  # 此处抛出错误


    def write_error(self, status_code, **info):
        print("write_error执行了,msg=%s" % info["msg"])

    def on_finish(self):
        print("on_finish执行了")

# 设置路由列表
urls = [
    (r"/", Home),
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls, **settings)
    server = HTTPServer(app)
    # 设置监听的端口和地址
    server.listen(options.port)
    server.start(1)
    ioloop.IOLoop.current().start()

视图执行顺序

没有异常

  • set_defautl_headers()
  • initialize()
  • prepare()
  • 视图http方法()
  • on_finish()

有异常

  • set_default_headers()
  • initialize()
  • prepare()
  • 视图http方法()
  • set_default_headers()
  • write_error()
  • on_finish()

冲刷缓存

事实上,在tornado提供的视图操作中,视图中提供了一个 _write_buffer列表用于暂时缓存提供给客户端的数据, 这个 _write_buffer就是输出缓冲区

self.write()本质上来说是将chunk数据块写到输出缓冲区中。所以才出现在视图中多次调用self.write()输出数据的情况,因为self.write根本没有输出数据,而是把数据写入到了输出缓冲区里面. 如果没有其他操作干预的情况下,则视图方法处理完成以后,会讲输出缓冲区中所有的数据冲刷出来响应给客户端。

除了self.write()方法以外,tornado还提供了2个方法用于在视图中冲刷缓存数据到客户端的。

self.flush() 立刻把数据从输出缓冲区冲刷出去。

self.finish()立刻把数据从输出缓冲区冲刷出去。但是与self.flush()不同的是, self.finish()执行了以后, 后面的所有输出调用都不在支持.也就不能返回给客户端。

from tornado import ioloop
from tornado import web
from tornado.httpserver import HTTPServer
from tornado.options import define, options, parse_command_line
settings = {
    'debug': True,
}

define("port", default=8888, type=int, help="设置监听端口号,默认为8888")

class Home(web.RequestHandler):
    def get(self):
        import time
        self.write("hello,get1")
        self.flush()
        time.sleep(3)
        self.write("hello,get2")
        self.flush()
        time.sleep(3)
        self.write("hello,get3")
        self.flush()
        self.finish("这里一般不写任何内容,表示视图处理结束")
        self.write("hello,get4")

# 设置路由列表
urls = [
    (r"/", Home),
]

if __name__ == "__main__":
    # 创建应用实例对象
    parse_command_line()
    app = web.Application(urls, **settings)
    server = HTTPServer(app)
    # 设置监听的端口和地址
    server.listen(options.port)
    server.start(1)
    ioloop.IOLoop.current().start()

用户认证

tornado提供了装饰器tornado.web.authenticated与视图内置方法get_current_user允许我们轻松的实现用户认证功能。

装饰器authenticated依赖于请求处理类中的self.current_user属性来进行判断用户是否通过认证,如果self.current_user值为假(None、False、0、""等),任何GET或HEAD请求都将把访客重定向到settings配置中login_url设置的URL,而非法用户的POST请求将返回HTTPError(403)异常, Forbidden。

from tornado import web
from tornado import ioloop
settings = {
    'debug': True,
    # 登录页面的url地址
    "login_url": r"/login"
}

from tornado.web import authenticated

class HttpRequest(web.RequestHandler):
    def get_current_user(self):
        username = self.get_argument("username", "")
        password = self.get_argument("password", "")

        if username == "root" and password == "123":
            return username

class Home(HttpRequest):
    @authenticated
    def get(self):
        self.write("hello,用户个人中心")

    @authenticated
    def post(self):
        self.write("hello,用户中心")

class UserLogin(web.RequestHandler):
    def get(self):
        self.write("登录页面")

urls = [
    (r"/", Home),
    (settings["login_url"], UserLogin),
]

if __name__ == '__main__':
    app = web.Application(urls,**settings)
    app.listen(port=8888)
    ioloop.IOLoop.current().start()

模板语法及内部函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {# 模板注释 #}
    <p>name={
   
   {name}}</p>
    <p>name={
   
   {info['name']}}</p>
    <p>{
   
   {"-".join(address)}}</p>
    <p>{
   
   {money_format(money)}}</p>
</body>
</html>

# 判断
{% if ... %}
{% elif ... %}
{% else ... %}
{% end %}

# 遍历
{% for ... in ... %}
{% end %}

# 循环
{% while ... %}
{% end %}

# 导包
{% from ... import ... %}
{% import ... %}
# 加载其他模板
{% include ... %}
# 输出原始数据
{% raw ... %}

# 语句/局部变量
{% set 变量名=变量值 %}

# 异常处理
{% try %}...{% except %}...{% else %}...{% finally %}...{% end %}
# 模板继承
{% extends *filename* %}
{% block 模板块名称} {% end %}

# 输出转义数据,tornado在配置中允许通过autoescape=None设置全局转义
{
   
   { escape(text) }}
# 静态文件存储路径
{
   
   { static_url("style.css") }}
# 路由反解析
reverse_url("路由别名")

# CSRF防范机制,CSRF也叫XSRF
# tornado开启csrf必须在配置中进行设置 xsrf_cookies = True
# 补充:
# 在前后端分离项目中,客户端可以通过cookie来读取XSRFToken,cookie名称为_xsrf,请求头必须名称:X-XSRFToken
# 在视图方法中可以通过 self.xsrf_token 来获取 XSRFTokentoken
{% module xsrf_form_html() %}

猜你喜欢

转载自blog.csdn.net/qq_45066628/article/details/112854196
今日推荐