13. tornado.httputil.HTTPFile对象
- tornado.httputil.HTTPFile对象作用:
它是接收到的文件的对象 - 属性
filename:文件的实际名字
body: 文件的数据实体
content_type:文件的类型
在templates中新建upload.html
templates/upload.html中简单的上传页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="file" name="file"/>
<input type="file" name="img"/>
<input type="submit" value="上传">
</form>
</body>
</html>
index的添加:
#tornado.httputil.HTTPFile对象
class UpfileHandler(RequestHandler): #上传文件
def get(self, *args, **kwargs):
self.render("upload.html") #访问页面upfiles.html
def post(self, *args, **kwargs):
files = self.request.files #从request这种拿到files
print(files)
self.write("上传成功")
application添加:
# http:127.0.0.1:9000/upload
(r"/upload", index.UpfileHandler),
新建text文本,写上who are you ,上传后
#(浏览器输出)上传成功
#(pychar输出){'file': [{'filename': '新建文本文档.txt', 'body': b'who are you!', 'content_type': 'text/plain'}]}#上传两个相同类型的文件
#(pychar输出){'file': [{'filename': '新建文本文档.txt', 'body': b'who are you!', 'content_type': 'text/plain'},{'filename': '新建文本文档2.txt', 'body': b'who are you!', 'content_type': 'text/plain'}]}#"file"就是<input type="file" name="file"/> 中的name
#"filename"就是上传的文件的名字
#“body”就是文件的内容#而相对于<input type="file" name="img"/>,上传为文件时
#"filename"就是上传的图片的名字
#"body"内容就会变成字节码b"......"
#“content_type”就是图片的类型
{"img":[{'filename': 'tupian.png', 'body': b'.......................', 'content_type': 'image/png'}]}
#如果上传多个不同类型的文件,request拿到files结构:
{
'file': [
{
'filename': '新建文本文档.txt', 'body': b'who are you!', 'content_type': 'text/plain'
},
{
'filename': '新建文本文档2.txt', 'body': b'who are you!', 'content_type': 'text/plain'
}
],
"img":[
{
'filename': 'tupian.png', 'body': b'.......................', 'content_type': 'image/png'
}
]
}
完整版上传:
import os
import config
class UpfileHandler(RequestHandler): # 上传文件
"""
self.request.files结构:
{'file': [{'filename': '新建文本文档.txt', 'body': b'who are you!', 'content_type': 'text/plain'},{'filename': '新建文本文档2.txt', 'body': b'who are you!', 'content_type': 'text/plain'}],"img":[{'filename': 'tupian.png', 'body': b'.......................', 'content_type': 'image/png'}]}
"""
def get(self, *args, **kwargs):
self.render("upload.html")
def post(self, *args, **kwargs):
filesDict = self.request.files
for inputname in filesDict:
fileArr = filesDict[inputname] # 拿到对应key的value
for filesObj in fileArr: # 又拿到key
# 存储路径
filePath = os.path.join(config.BASE_DIRS, "upfile/" + filesObj.filename)
# filesObj.filename新建file。字典取到上传文件的名字,并新建
with open(filePath, "wb") as f: # 打开新建的文件 ( w+用在纯文本上,wb+可以用在Exe文件)
f.write(filesObj.body) # 一样的字典形式拿到value,写入 文本的body字段的内容,即value
self.write("成功")
def check_xsrf_cookie(self):
# 非常有用的在单页面禁用xsrf_cookie的检查
return True
14.响应输出
- write
原型:self.write(chunk) # chunk是响应浏览器的数据
作用:
1. 将chunk数据写到输出缓冲区。
-----------缓冲区刷新:1.程序结束;2.手动刷新;3缓冲区满;4.遇到\n
2.利用write方法写json数据
##刷新缓冲区
self.finish
刷新缓冲区,并关闭当前请求通道,即后面的数据不在传输
##缓冲区的内容输出到浏览器不用等待请求处理完成
self. flush()
self.write()会先把内容放在缓冲区,正常情况下,当请求处理完成的时候会自动把缓冲区的内容输出到浏览器,但是可以调用 self.flush()方法,这样可以直接把缓冲区的内容输出到浏览器,不用等待请求处理完成.
index.py添加:
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")
#配置application中的url
(r"/write", index.WriteHandler), #响应输出
(r"/json1", index.Json1Handler), # 测试json1
(r"/json2", index.Json2Handler), # 测试json2
Json2Handler,Json1Handler之前有实现。。。。。
##序列化
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
#预先设置报文头
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
##设置响应头
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里的默认设置字段
#预先设置报文头
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
##设置状态码
self.set_status(status_code,reason=None)
作用:为响应设置状态码
self.set_status(404,"bad boy")
参数:status_code (状态码的值,int类型)
如果reason=None,则状态码必须为正常值,列如999
reason (描述状态码的词组,string字符串类型)#设置状态码
class StatusHandler(RequestHandler):
def get(self, *args, **kwargs):
self.set_status(404,reason="Dont find!")
self.write("*****") #返回Status Code:404 Dont find!
##重定向
self.redirect()
重定向跳转到其他页面,比如self.redirect("/write")跳转到http://127.0.0.1:9000/wtite#重定向
class RedirectHandler(RequestHandler):
def get(self,*args,**kwargs):
self.redirect("/write") #self.redirect重定向##抛出HTTP错误状态码,默认为500, tornado会调用write_error()方法并处理
self.send_error(status_code=500,**kwargs) # 抛出错误##接收错误,并处理。所以说上面这两个必须连用。
self.write_error(status_code,**kwargs) # 接收返回来的错误并处理错误
#自定义错误页面
访问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")
注册这个类,
# http://127.0.0.1:9000/error?flag=0
(r"/error", index.ErrorHandler),
http://127.0.0.1:9000/error?flag=4
15.接口调用顺序
方法:
1.def initialize(),
作用:初始化
2.def preare()方法
作用:预处理方法,在执行对应的请求方法之前调用
注意:任何一种http请求都会执行prepare方法
所以可以在这里进行反爬虫,验证用户是否符合条件。
3.HTTP方法
get:在传参的时候会将参数拼接到UTL的后面;速度快,效率高,不安全,传输数据量小
post:在传参时则是单独打包并发送;传输慢,效率低,传输数据量大,安全;(一般修改服务器的数据时就用post,其他时候就用get)
head :类似get请求,只是相应中没有具体的内容,用户获取报文头
delete:请求服务器到删除指定的资源
put :从客户端向服务器传送指定内容
patch:请求修改局部内容
options:返回URL支持的所有HTTP方法
4.def set_default_headers()
作用:设置响应头
5.def write_error()
作用:出现异常就提醒(如邮件提醒)机制并跳转到错误页面
6.def on_finish()
作用:在请求处理结束后执行,在该方法中进行一个资源的清理释放(各种方法调用中开启的空间释放–内存),或者是日志处理(当请求完成后的访问信息记录)
注意:尽量不要在该方法中进行响应输出
比如进行get请求完成后调用on_finish(),进行资源的清理释放
class IndexHandler(RequestHandler):
def get(self, *args, **kwargs):
pass
def post(self, *args, **kwargs):
pass
def on_finish(self):
pass
顺序:
- 在正常情况未抛出错误时的顺序:
set_default
initialize
prepare
get/post
on_finish
测试如下:
views/index中的代码:
class TextHandler(RequestHandler):
def initialize(self):
print("initialize")
def prepare(self):
print("prepare")
def get(self,*args,**kwargs): #或者post
print("get")
def set_default_headers(self):
print("set_default_hearders")
def write_error(self,status_code,**kwargs):
print("write_error")
def on_finish(self):
print("on_finish")
#application中配置路由
(r"/test",index.TextHandler) , #测试接口调用顺序
#浏览访问后
#(pycharm输出):
set_default_hearders
initialize
prepare
get
on_finish
- 在抛出错误的情况下的顺序
set_default_headers
initialize
prepare
get
set_default_headers
write_error
on_finish
测试如下:
views/index中
class TextHandler(RequestHandler):
def initialize(self):
print("initialize")
def prepare(self):
print("prepare")
def get(self,*args,**kwargs):
print("get")
self.send_error(500)
self.write("抛出错误500")
def set_default_headers(self):
print("set_default_headers")
def write_error(self,status_code,**kwargs):
print("write_error")
self.write("500服务器错误")
def on_finish(self):
print("on_finish")
浏览器访问后 #(pycharm输出):
set_default_headers
initialize
prepare
get
set_default_headers
write_error
on_finish
ERROR:tornado.access:500 GET /text (127.0.0.1) 0.83ms
ERROR:tornado.application:Uncaught exception GET /text (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:9000', method='GET', uri='/text', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Host': '127.0.0.1:9000', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'keep-alive', 'Cookie': 'csrftoken=kYvwi4JlbaFXkvvxF4qpEaScrcMF68e4', 'Upgrade-Insecure-Requests': '1'})
Traceback (most recent call last):
File "/home/hlx2/anaconda3/lib/python3.6/site-packages/tornado/web.py", line 1509, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "/home/hlx2/Linux-64/tornado_tutorial/views/index.py", line 18, in get
self.write("抛出错误500")
File "/home/hlx2/anaconda3/lib/python3.6/site-packages/tornado/web.py", line 708, in write
raise RuntimeError("Cannot write() after finish()")
RuntimeError: Cannot write() after finish()
https://blog.csdn.net/weixin_43097301/article/details/84981441