#Python3中tornado高并发框架 - Go语言中文社区

#Python3中tornado高并发框架


Python3中tornado高并发框架


在这里插入图片描述

简介:

Tornado是一种 Web 服务器软件的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。
得利于其非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。
反向代理服务器后端的Tornado实例:
在这里插入图片描述

在这里插入图片描述

1.单线程

tornado.web:基础web框架模块
tornado.ioloop:核心IO循环模块,高效的基础。封装了:
1.asyncio 协程,异步处理
2. epoll模型:水平触发(状态改变就询问,select(),poll()), 边缘触发(一直询问,epoll())
3.poll 模型:I/O多路复用技术
4.BSD(UNIX操作系统中的一个分支的总称)的kqueue(kueue是在UNIX上比较高效的IO复用技术)

epoll和kqueue的区别如下:

'epoll'仅适用于文件描述符,在Unix中,一切都是文件”。
这大多是正确的,但并非总是如此。例如,计时器不是文件。
信号不是文件。信号量不是文件。进程不是文件。
(在Linux中)网络设备不是文件。类UNIX操作系统中有许多不是文件的东西
。您不能使用select()/ poll()/ epoll来复制那些“事物”。
Linux支持许多补充系统调用,signalfd(),eventfd()和timerfd_create()
它们将非文件资源转换为文件描述符,以便您可以将它们与epoll()复用。
epoll甚至不支持所有类型的文件描述符;
 select()/ poll()/ epoll不适用于常规(磁盘)文件。
 因为epoll 对准备模型有很强的假设; 监视套接字的准备情况,
 以便套接字上的后续IO调用不会阻塞。但是,磁盘文件不适合此模型,因为它们总是准备就绪。
 
kqueue 中,通用的(struct kevent)系统结构支持各种非文件事件
import tornado.web		#tornado.web:基础web框架模块
import tornado.ioloop		#tornado.ioloop:核心IO循环模块,高效的基础。

class IndexHandler(tornado.web.RequestHandler):      
							#类比Django中的视图,相当于业务逻辑处理的类
    def get(self):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

if __name__=="__main__":

    """
    实例化一个app对象
    Application:他是tornado.web框架的核心应用类,是与服务器对应的一个接口
    里面保存了路由映射表,还有一个listen方法,可以认为用来创建一个http的实例
    并绑定了端口
    """
    
    app = tornado.web.Application([
            (r"/" ,IndexHandler),
        ])

    app.listen(8888)    	#绑定监听端口,但此时的服务器并没有开启监听
    tornado.ioloop.IOLoop.current().start()
    
    			#Application([(r"/" ,IndexHandler),])传入的第一个参数是
    			#路由路由映射列表,但是在此同时Application还能定义更多参数
    			
			     #IOLoop.current():返回当前线程的IOLoop实例
			    #例如实例化对象 ss=run() ,ss.start()
			    #start():启动了IOloop实例的循环,连接客服端后,同时开启了监听
    

原理如下:

linux-epoll进行管理多个客服端socket
tornado-IoLoop不断进行询问epoll:小老弟,有没有我需要做的事吗?    
当epoll返回说:老哥,有活了
tornado-IoLoop将活上传给tornado.web.Application
tornado.web.Application中有 路由映射表
就会将socket进行一个路由匹配
把socket匹配给相对应的Handler(处理者)
Handler(处理者)处理后将数据返回给对应的socket,
(这里因为可能会延时响应,所以这里进行异步处理)
socket然后再传给了客服端浏览器。

在这里插入图片描述
图片将就看啊,手残党。。

2.多线程

新加模块如下:

tornado.httpserver  	#tornado的HTTP服务器实现

注意:
在windows中运行多进程会报错:
AttributeError: module ‘os’ has no attribute 'fork’
这是因为fork这个系统命令,只在linux中才有用,
如果你是在windows, win7、winxp中运行的话就会出错。
所以把上面的python文件,拷贝到linux的系统中再运行就没问题了.
这个错误我暂时没有解决,后续补上。

import tornado.web
import tornado.ioloop
import tornado.httpserver  	#tornado的HTTP服务器实现


class IndexHandler(tornado.web.RequestHandler):
    def get(self):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

if __name__=="__main__":

    app = tornado.web.Application([
            (r"/" ,IndexHandler),
        ])
    httpServer = tornado.httpserver.HTTPServer(app)

    #httpServer.listen(8000)  #多进程改动原来的这一句

    httpServer.bind(8888)      #绑定在指定端口
    httpServer.start(2)
                                #默认(0)开启一个进程,否则对面开启数值(大于零)进程
                          #值为None,或者小于0,则开启对应硬件机器的cpu核心数个子进程
                            #例如 四核八核,就四个进程或者八个进程
    tornado.ioloop.IOLoop.current().start()


#app.listen(),只能在单进程中使用

#多进程中,虽然torna给我们提供了一次性启动多个进程的方式,但是由于一些问题,不建议使用上面打的方式启动多进程,而是手动启动多个进程,并且我们还能绑定不同的端口

问题如下:

#1.每个子进程都会从父进程中复制一份IOLoop的实例,
如果在创建子进程前修改了IOLoop,会影响所有的子进程

#2.所有的进程都是由一个命令启动的,无法做到不停止服务的情况下修改代码。
修改单个进程是需要关掉所有进程,影响客服服务使用。

#3.所有进程共享一个端口,向要分别监控很困难。

所以:我们手动启动多个进程,并且我们还能绑定不同的端口,进行单个进程操作。

3.options模块

新运用模块如下:

tornado.options模块:提供了全局参数的定义,储存和转换

属性和方法
tornado.options.define()
原型tornado.options.define(name, default=None, type=None, help=None, metavar=None,multiple=False, group=None, callback=None)

常用参数:

# name(选项变量名),必须保证其唯一性,
否则报错"options 'xxx' already define in '....'"

#default(设置选项变量的默认值),默认为None

#type(设置选项变量的类型),str,int,float,datetime(时间日期),等,
从命令行或配置文件导入参数时,会根据类型转换输入的值。
如果不能转化则报错,如果没有设置type的值,
会根据default的值的类型进行转换,比如default的值 8000,
而传给type的为‘8080’字符串,
则会转换成int类型。如果default也没有设置,则不转化

#multipe(设置选项变量是否为多个值),默认False 比如传递为列表,
列表包括了多个值,就要改为Ture。

#help 选项变量的提示信息。自主添加,比如  help="描述变量"

#方法
#tornado.options.options
#全局的options对象,所有定义的选项变量都会作为该对象的属性

#获取参数的方法(命令行传入)
#1. tornado.options.parse_command_line()
#作用:转化命令行参数,接收转换并保存

#获取参数的方法(从配置文件导入参数)
#tornado.options.parse_config_file(path=)

1获取参数的方法(命令行传入)

import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options  #提供了全局参数的定义,储存和转换
from tornado.options import options #全局的options对象,所有定义的选项变量都会作为该对象的属性

#定义两个参数
tornado.options.define('port', default=8000, type=int)
tornado.options.define('list', default=[], type=str,multiple=True) #multiple=True接收多个值

class IndexHandler(tornado.web.RequestHandler):
    def get(self):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

if __name__=="__main__":
    tornado.options.parse_command_line()
            #转化命令行参数,接收转换并保存在tornado.options.options里面
    print('list',options.list)
    app = tornado.web.Application([
            (r"/" ,IndexHandler),
        ])
    httpServer = tornado.httpserver.HTTPServer(app)

    #httpServer.listen(8000)  #多进程改动原来的这一句

    httpServer.bind(options.port)      #绑定在指定端口
                        #全局的options对象,所有定义的选项变量都会作为该对象的属性
                        #这里就可以使用tornado.options.parse_command_line()保存的变量的值
    httpServer.start(1)
                                #默认(0)开启一个进程,否则对面开启数值(大于零)进程
                             #值为None,或者小于0,则开启对应硬件机器的cpu核心数个子进程
                            #例如 四核八核,就四个进程或者八个进程
    tornado.ioloop.IOLoop.current().start()

#注意这里不能直接启动,应为没有进行传值,那要在怎么启动,用命令行cmd进行
#cmd进行当前py文件目录 python server.py  --port=9000  --list=good,nice,cool

#启动
#> python server.py  --port=9000  --list=good,nice,cool
#启动的时候就指定了端口号,就会启动指定端口号的服务器,也就是说我们不用每次用都去修改我们的代码的端口
#(输出)list ['good', 'nice', 'cool']

2.获取参数的方法(从配置文件导入参数)
将上面的代码中的tornado.options.parse_command_line()进行更改为
tornado.options.parse_config_file(“config”)

#"config"为配置文件,这里因为是在同一级目录下,所以直接写文件名,如果不在则需要进行书写路径。
#需要创建名为config的普通文件,作为配置文件
在里面进行书写配置。
config配置文件 例如:

port=7000
list=["job","good","nice"]
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options  #提供了全局参数的定义,储存和转换
from tornado.options import options #全局的options对象,所有定义的选项变量都会作为该对象的属性

#定义两个参数
tornado.options.define('port', default=8000, type=int)
tornado.options.define('list', default=[], type=str,multiple=True) #multiple=True接收多个值

class IndexHandler(tornado.web.RequestHandler):
    def get(self):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

if __name__=="__main__":
    tornado.options.parse_config_file("config")
            #需要创建名为config的普通文件
    print('list',options.list)
    app = tornado.web.Application([
            (r"/" ,IndexHandler),
        ])
    httpServer = tornado.httpserver.HTTPServer(app)

    #httpServer.listen(8000)  #多进程改动原来的这一句

    httpServer.bind(options.port)      #绑定在指定端口
                        #全局的options对象,所有定义的选项变量都会作为该对象的属性
                        #这里就可以使用tornado.options.parse_command_line()保存的变量的值
    httpServer.start(1)
                                #默认(0)开启一个进程,否则对面开启数值(大于零)进程
                             #值为None,或者小于0,则开启对应硬件机器的cpu核心数个子进程
                            #例如 四核八核,就四个进程或者八个进程
    tornado.ioloop.IOLoop.current().start()

说明:这两种方法以后都不常用,常用的是文件配置,但是是.py文件进行配置。
因为书写格式人需要按照Python的语法要求,并且普通的文件不支持字典类型

4.最终的py配置文件

创建config.py文件编写配置文件
#定义字典
#新建文件config.py文件,配置模型:
options = {
‘port’:8080,
‘list’:[‘good’,‘nicd’,‘job’]
}

import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
import tornado1.config     #直接导入配置的py文件


class IndexHandler(tornado.web.RequestHandler):
    def get(self,*args,**kwargs):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

if __name__=="__main__":
    print('list=',tornado1.config.options["list"])
    app = tornado.web.Application([
            (r"/" ,IndexHandler),
        ])
    httpServer = tornado.httpserver.HTTPServer(app)

    httpServer.bind(tornado1.config.options["port"])      #绑定在指定端口
                        #全局的options对象,所有定义的选项变量都会作为该对象的属性
                        #这里就可以使用tornado.options.parse_command_line()保存的变量的值
    httpServer.start(1)
                                #默认(0)开启一个进程,否则对面开启数值(大于零)进程
                             #值为None,或者小于0,则开启对应硬件机器的cpu核心数个子进程
                            #例如 四核八核,就四个进程或者八个进程
    tornado.ioloop.IOLoop.current().start()

##其他的获取参数方式,

http://127.0.0.1:9000/error?flag=0
向error页面传递flag=0这个值,其中?表示传值
页面中接收flag

 def get(self, *args, **kwargs):
        flag = self.get_query_argument("flag")
get_query_argument()/get_query_arguments()/get_body_argument()/get_body_arguments()
上述四个获取值方法统一参数:(name, default=_ARG_DEFAULT, strip=True)

# name:获取name属性的值

default:设置默认值,如果没有参数传递过来,那么就是用默认值

strip: 去除左右空格

复制代码
# 使用get方式传递参数
    def get(self):
        # 获取单个键值
        get_a = self.get_query_argument('a')  # 如果同时传递多个a的参数,那么会采用后面覆盖前面的原则
        self.write(get_a)
        # 其中获取多个使用:get_query_arguments()
    # 使用post传递参数
    def post(self):
        # 接收单个参数
        post_a = self.get_body_argument('a')
        self.write(post_a)
        # 其中获取多个参数传递使用get_body_arguments()
复制代码
 

使用get_argument()/get_arguments()可以不区分post/get传递方式

def post(self):
        # 接收单个参数
        post_a = self.get_argument('a')
        self.write(post_a)
        # 其中获取多个参数传递使用get_arguments()
 

值得注意的是:使用上述方法获取参数只能够获取headers报头为"application/x-www-form-urlencoded"或者"multipart/form-data"的数据,如果想获取json或者xml方式传递的数据需要使用self.request方式获取

def post(self):
        self.write(self.request.headers.get('Content-Type'))  # 获取“application/json”类型传递
        # 如果想获取内容,可以使用self.request.body

5.关闭日志logging=none

当我们使用命令行传递参数parse_command_line()或者配置文件parse_config_file(path)传递参数是,tornado会默认开启日志,向终端打印信息。
比如在传递参数parse_command_line()类型中。
python
server.py --port=9000 --list=good,job,nice 启动py文件后
在进行网页登录本地地址(ipconfig可查看)192.168.22.33:7000进入后
cmd终端就会打印[I 181215 19:13:39 web:2162] 304 GET / (192.168.22.33) 1.00ms #I为信息(information) 或者 [W 181215 19:18:10 web:2162] 404 GET /index (192.168.43.145) 0.50ms #W为错误(wrong)

如果不想让终端打印
在tornado.options.parse_command_line()之前加上tornado.options.options.logging=None
或者在cmd中
python server.py --port=9000 --list=good,job,nice --logging=none

6.基本框架样式

在这里插入图片描述
1.static文件夹-----------------静态页面存放
2.templates文件夹-----------模板存放
3.upfile文件夹----------------上传文件存放
4.views文件夹----------------视屏存放
5.application文件-------------视屏编写
6.config文件 ------------------配置文件编写
7.server文件------------------服务编写


1.server文件基本样式

import tornado.web      #web框架模块
import tornado.ioloop       #核心IO循环模块
import tornado.httpserver       #tornado的HTTP服务
import tornado.options      #全局参数定义,存储和转化模块
import config     #导入自定义配置的py文件
import application  #导入自定义的应用程序模块
"""
#server
	服务设置
"""

if __name__=="__main__":
    app = application.Application          #处理请求服务类
    httpServer = tornado.httpserver.HTTPServer(app) #设置HTTP服务器 
    httpServer.bind(config.options["port"])      #绑定在指定端口
    httpServer.start(1)                         #线程数
    tornado.ioloop.IOLoop.current().start()     #启动

2.congif文件

"""
#config
	存放参数
"""

options ={
    "port" : 8000,
}


"""
#config
	配置文件,相当于django里面的setting
	配置application应用程序路由,即文件地址路径

	##BASE_DIRS = os.path.dirname(__file__)
		当前file文件路径

	##os.path.join(BASE_DIRS,"static")
		拼接路径:如(BASE_DIRS/static),当然BASE_DIRS=当前文件的父类的文件路径
"""

import os
BASE_DIRS = os.path.dirname(__file__)
setting = {
    "static_path":os.path.join(BASE_DIRS,"static"),  #静态文件
    "template_path":os.path.join(BASE_DIRS,"templates"),  #视图
    "debug":True ,    #修改完文件后服务自动启动
    # "autoescape":None, #关闭自动转义
    "cookie_secret":"OrGWKG+lTja4QD6jkt0YQJtk+yIUe0VTiy1KaGBIuks",  #混淆加密
    "xsrf_cookies":True,  #开启xsrf保护
    "login_url":"/login",
}

3.application文件夹中Application

import  tornado.web
from views import index
from config import  setting #导入配置文件setting
"""
#application中设置一个函数子类Application
	存放路由
"""

class Application(tornado.web.Application):  #tornado.web.Application的子类
    def __init__(self):
        handlers=[
            (r"/",index.IndexHandler)
            
            #(r"/(.*)$",tornado.web.StaticFileHandler{"path":os.path.join(config.BASE_DIRS,"static/html"),"default_filename":"index.html"}),
             #StaticFileHandler应用静态文件,注意要放在所有路由的下面。用来放静态主页
             
			(r"/(.*)$", index.Static_FileHandler,{"path": os.path.join(config.BASE_DIRS, "static/html"), "default_filename": "index.html"}),
			#由于我们想让用户进入主页即自动设置xsrf_cookie,所以我们用到继承 的方式,让index.StaticFileHandler继承父类tornado.web.StaticFileHandler,再向里面添加设置xsrf设置
			
        ]
        
        super().__init__(handlers,**setting)
        
   #super()函数是用于调用父类(超类)的一个方法。
   #Python3可以使用直接使用super().xxx代替super(Class, self).xxx:
   #执行的是tornado.web.Application的init,再将handlers传参
   #添加配置文件,参数里面加入**setting,(即**kwargs)

4.views中的index基本样式

import tornado.web
from tornado.web import RequestHandler
"""
#views中的index
	存放视图
"""

class IndexHandler(RequestHandler):
    def get(self,*args,**kwargs):   #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求

7.config文件,配置解析

import os
BASE_DIRS = os.path.dirname(__file__)
setting = {
    "static_path":os.path.join(BASE_DIRS,"static"),
    "template_path":os.path.join(BASE_DIRS,"templates"),
    "debug":True      
}

1.debug

debug:
设置tornado是否工作在调试模式下,默认为debug:False即工作在生产模式下(上线后)。
设置为True即在开发模式(开发中调试)。

debug:True特性如下:
##1.自动重启:
        tornado应用会监控源代码文件,当有保存改动时重新启动服务器,会减少手动重启的时间和次数,提高开发效率。
        但是:如果保存后代码有错误导致重启失败后,将会变为手动重启,再次重启可能由于之前的端口不是正常关闭,
        而导致端口没有被释放,这时候重新切换端口,或者等待端口释放,即可。

   		 如果只想引用这一个特性:通过编写 autoreload = True 进行设置,在config配置文件中字典模式"autoreload" : True

##2.取消缓存编译的模板
    用于开放阶段:
        修改代码后,并没有发生改变,是因为缓存的存在,并没有应该用达到实际文件上。
        通过参数compiled.template_cache=False设置,但在配置文件中用字典形式"compiled.template_cache":False设置

##3.取消缓存静态文件的hash值
    用于开发阶段:
        加载css文件的时候,tornado中在css文件后面还有hash值(比如a.css?hash=jsajdjafahafasddasdfasdadsasd)
        而取消后,相当于为新文件加载,后面得hash值就会变,这样我们就能看到每一次更改后的效果
        可以通过参数设置static_hash_cache=False单独设置,配置文件中字典形式"static_hash_cache":False设置

##4.提供追踪信息(不常用)
        没有捕获异常时,会生成一个追中页面的信息
        可以通过参数serve_traceback=True设置 , 配置文件中字典形式"serve_traceback":True设置

2.static_path
设置静态文件目录

3.static_path
设置模板目录

8.application文件夹,路由解析

import  tornado.web
from views import index
from config import  setting #导入配置文件中的setting
"""
#application中设置一个函数子类Application
    存放路由
    
    ##简单的形式(r"/",index.IndexHandler)
    
    ## 传参形式(r"/good",index.GoodHandler,{"str1":"入门小白","str2":"高阶大神"}),这里是服务器自己传参,如果要进行用户传参,则对应修改编辑方法
"""

class Application(tornado.web.Application):  #tornado.web.Application的子类
    def __init__(self):
        handlers=[
            (r"/",index.IndexHandler),
            (r"/good",index.GoodHandler,{"str1":"入门小白","str2":"高阶大神"}),
            (r"/write",index.WriteHandler),
            (r"/json1",index.Json1Handler),     #测试json1
            (r"/json2", index.Json2Handler),     #测试json2
            (r"/header",index.HanderHander) ,    #响应头字段(Respose Headers)
            (r"/status",index.StatuscodeHander),    #状态码
            tornado.web.url(r"/boy",index.BoyHandler,{"word3":"who","word4":"are you"},name="boy"), #反向解析
        ]
        super().__init__(handlers,**setting)
        #super()函数是用于调用父类(超类)的一个方法。
        #Python3可以使用直接使用super().xxx代替super(Class, self).xxx:
        #执行的是tornado.web.Application的init,再将handlers传参
        #添加配置文件,参数里面加入**setting,(即**kwargs)

application中设置一个函数子类Application
存放路由

##简单的形式(r"/",index.IndexHandler)

##传参的形式(r"/good",index.GoodHandler,{"str1":"入门小白","str2":"高阶大神"}),
	对应的在index里面建立对应GoodHandler类后,
	定义接收函数def initialize(self,str1,str2),然后在调用str1,str2
	这里是服务器自己传参,如果要进行用户传参,则对应修改编辑方法

9.views中的index,解析

#views中的index
存放视图

##def initialize 
    接收传递过来的参数,并以 self.参数=参数 形式进行绑定
    
##self.write
    将chunk(数据块)数据写到缓冲区

##刷新缓冲区
	self.finish
   		 刷新缓冲区,并关闭当前请求通道,即后面的数据不在传输
   		 
##缓冲区的内容输出到浏览器不用等待请求处理完成
	self. flush()
		self.write()会先把内容放在缓冲区,正常情况下,当请求处理完成的时候会自动把缓冲区的内容输出到浏览器,但是可以调用 self.flush()方法,这样可以直接把缓冲区的内容输出到浏览器,不用等待请求处理完成.
		
##序列化
	json,jsonStr = json.dumps()
        需要导入json库,对应的Handler中编写字典, jsonStr = json.dumps(per) 将字典转化为json的字符串
         #(浏览器输出){"name": "nick", "age": 18, "height:": 170, "weight": 70} 
         但是你会发现,其实我们不需要这样写,直接用write也能转化。json还要进行下文的设置响应头
         但是前者json转化的在谷歌浏览器F12中Network中json1文本中的Respose Headers里面,
         Content Type 为 text/heml,而后者write转换后为appliction/json。
         text/heml浏览器会将这个当成页面进行渲染,所以应为json类型
        ###在线解析json数据结构 ,https://c.runoob.com/front-end/53  
    
##设置响应头
	self.set_header(name,value)
        self.set_header("Content-Type","applictions/json;charset=UTF-8")
        self.set_header("good","boy")   #自定义设置
        作用:手动设置一个名为name值为value的响应头字段(Respose Headers)
        参数:name:字段名称
            value:字段值
        
 ###text/html和text/plain的区别
        1、text/html的意思是将文件的content-type设置为text/html的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
        2、text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理

##默认的headers
	set_default_headers()
        作用:
            def set_default_headers(self):
            在进入http响应方法之前被调用,可以重写该方法来预先设置默认的headers
            这样类下面的各种方法都不用再去设置header了,默认为set_default_headers里面的
            以后规范都在set_default_headers里面进行设置header
        注意:
            在http处理方法中(这里暂为get方法)使用set_header设置的子弹会覆盖set_default_headers里的默认设置字段

##设置状态码
	self.set_status(status_code,reason=None)
        作用:为响应设置状态码
         self.set_status(404,"bad boy")
        参数:status_code (状态码的值,int类型)
                    如果reason=None,则状态码必须为正常值,列如999
            reason (描述状态码的词组,sting字符串类型)
   
##重定向
	self.redirect()
		重定向跳转到其他页面,比如self.redirect("/write")跳转到http://127.0.0.1:9000/wtite
		
##抛出HTTP错误状态码,默认为500,   tornado会调用write_error()方法并处理
	self.send_error(status_code=500,**kwargs)
		抛出错误


##接收错误,并处理。所以说上面这两个必须连用。
	self.write_error(status_code,**kwargs)
		接收返回来的错误并处理错误
import  tornado.web
from tornado.web import RequestHandler
import json
#------------------------------------------------
class IndexHandler(RequestHandler):
    def get(self,*args,**kwargs):      #处理get请求的,并不能处理post请求
        self.write("good boy")      #响应http的请求
        
#-------------------------------
class WriteHandler(tornado.web.RequestHandler):
    def get(self,*args,**kwargs):
        self.write("good boy1")
        self.write("good boy2")
        self.write("good boy3")
        self.finish()   #刷新缓存区,并关闭请求通道,导致后面的good boy4无法传输
        self.write("good boy4")
#---------------------------------------------------
class Json1Handler(RequestHandler):
    def get(self, *args, **kwargs):
        per = {
            "name":"小白",
            "gae":"22",
            "height":170,
            "weight":60,
        }
        jsonStr = json.dumps(per)  #导入json库,将字典转化为json字符串
        self.set_header("Content-Type", "applictions/json;charset=UTF-8")
        self.write(jsonStr)
        
#----------------------------------------------------------------------
class Json2Handler(RequestHandler):
    def get(self, *args, **kwargs):
        per = {
            "name":"小白",
            "gae":"22",
            "height":170,
            "weight":60,
        }
        self.write(per)
#----------------------------------------------------------#------------
#预先设置报文头
class Headerhandler(RequestHandler):
    def set_default_headers(self):
        self.set_header("Content-Type", "applictions/json;charset=UTF-8") #预先设置报文头
    def post(self, *args, **kwargs):  #下面的就不必再次书写了
        pass
    def get(self, *args, **kwargs):
        pass
#------------------------------------------------------
#设置状态码
class StatusHandler(RequestHandler):
    def get(self, *args, **kwargs):
        self.set_status(404,reason="Dont find!")
        self.write("*****")  #返回Status Code:404 Dont find!
#------------------------------------------------        
#重定向
class RedirectHandler(RequestHandler):
    def get(self,*args,**kwargs):
        self.redirect("/write")    #self.redirect重定向
        
#------------------------------------------------------
#自定义错误页面
访问http://127.0.0.1:9000/error?flag=0 进行测试

class ErrorHandler(RequestHandler):
    def write_error(self, status_code, **kwargs):
        if status_code==500:
            code = 500
            #返回500界面
            self.write("服务器内部错误")
        elif  status_code==400:
            code = 400
            #返回404界面
            self.write("预先设置错误")
        self.set_status(code)
    def get(self, *args, **kwargs):
        flag = self.get_query_argument("flag")# 获取单个键值
        
        #self.get_query_argument('a')  # 如果同时传递多个a的参数,那么会采用后面覆盖前面的原则
        
        if flag == "0":
            self.send_error(500)
            #注意在self.send_error(500)以下同级的内容不会继续执行,
        self.write("right")
    
#-------------------------------------
#反向解析
class IndexHandler(RequestHandler):
    def get(self,*args,**kwargs):      #处理get请求的,并不能处理post请求
        # self.write("good boy")      #响应http的请求
        url = self.reverse_url("boy") #找到别名为boy的url
        self.write("<a href='%s'>跳转到另一个页面</a>"%(url))		#点击a标签跳转到页面/boy
        
class BoyHandler(RequestHandler):
    def initialize(self,word3,word4):         #该方法会在http方法(这里为get方法)之前调用
        self.word3=word3
        self.word4= word4
    def get(self, *args, **kwargs):
        print(self.word3,self.word4)
        self.write("good boy")

11. tornado.web.RequestHandler传参

11.1 利用HTTP协议向服务器传递参数

  1. 提取URI的特定部分
  2. get方式传递参数
  3. post方式传递参数
  4. 既可以获取get请求,也可以获取post请求
  5. 在http报文中增加自定义的字段

1提取URI的特定部分

(r"/movies/(w+)/(w+)/(w+)",index.MoviesHandler) # w匹配包括下划线的任何单词字符 +只有一个 *零到多个
(r"/movies1/(?Pw+)/(?Pw+)/(?Pw+)",index.movies1Handler)

class MoviesHandler(RequestHandler):
    def get(self, h1,h2,h3,*args, **kwargs):  #要接收几个就加几个在,而用字典{}传参的用initializ
#application中
 class Application(tornado.web.Application):  #tornado.web.Application的子类
    def __init__(self):
        handlers=[
        		#(省略部分url)
    
        		(r"/movies/(w+)/(w+)/(w+)",index.MoviesHandler)  
        		#//127.0.0.1:9000/movies/good/boy/job  
        		# w匹配包括下划线的任何单词字符  +只有一个  *零到多个
        		
        		(r"/movies1/(?P<p1>w+)/(?P<p2>w+)/(?P<p3>w+)",index.movies1Handler)
        		#//127.0.0.1:9000/movies/good/boy/job 
        		
        ]
#views/index中
from tornado.web import RequestHandler

class MoviesHandler(RequestHandler):
    def get(self, h1,h2,h3,*args, **kwargs):  #要接收几个就加几个在,而用字典{}传参的用initializ
        print(h1 + "-"+h2+"_"+h3)
        self.write("move go !")
#----------------------------------
class movies1Handler(RequestHandler):
    def get(self, p1,p2,p3,*args, **kwargs):  #要接收几个就加几个在,而用字典{}传参的用initializ
        print(p1 + "-"+p2+"_"+p3)
        self.write("move go to !")
访问http://127.0.0.1:9000/movies/good/boy/job 
#(浏览器输出):move go!
#(pycharm输出):good-boy_job

#--------------------------------------------------
访问http://127.0.0.1:9000/movies1/good/boy/job 、
#(浏览器输出):move go to !
#(pycharm输出):good-boy_job

2get方式传递参数
路由比如(r"/movies2",index.Movies2Handler)
self.get_query_argument(name,default=ARG_DEFAULT(参数默认值),strip=True)#原型,这样去拿到参数a,b,c的值
self.get_query_arguments(name,strip=True)有重复的参数,参数原型

#127.0.0.1:8000/movies2?a=1&b=2&c=3第一种情况
#127.0.0.1:8000/movies2?a=1%20%20&b=2%20%20%20&c=3第二种情况
#127.0.0.1:8000/movies2?a=1&a=2&c=3第三种情况

#views/index中比如接收参数
class Movies2Handler(RequestHandler):   #127.0.0.1:8000/movies2?a=1&b=2&c=3
    def get(self, *args, **kwargs):
		self.get_query_argument(name,default=ARG_DEFAULT(参数默认值),strip=True)#原型,这样去拿到参数a,b,c的值
				 #self.get_query_arguments(name, strip=True)有重复的参数,参数原型
				 
  参数:
	name:
			从get请求参数字符传中返回指定参数的值,如果出现多个同名参数,则返回最后一个的值
	default:
			设置未传的参数时),返回默认的值 ,比如这里传过来一个a(存在127.0.0.1:8000/movies2?a=1&b=2&c=3)没有任何赋值,而default=100,则默认a=100。
			如果传过来没有的值,default也没有设置,比如d没有这样的值,会跑出一个错误:tor
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_43097301/article/details/84981441
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢