javascript - Tornado stream_request_body:如何将自定义错误消息写入文档元素?
问题描述
我有一个用于将文件上传到服务器的tornado
应用程序。stream_request_body
文件选择是一个 HTML 表单,其中 JSonsubmit
函数用于执行上传处理程序。JS 功能async
与await fetch
. 如果用户选择的文件超过最大允许大小,那么我使用self.set_status(400)
. def prepare(self)
在这种情况下,我还想发送/写入一个文本字符串(self.write('File too big')
?),该字符串应该显示在文档中的元素中,作为向用户提供的信息,我该怎么做?
使用我当前的 JS 脚本,我在浏览器控制台中收到错误:
Promise { <state>: "pending" }
TypeError: Response.json: Body has already been consumed.
我在设置tornado
服务器时遇到的另一个问题是,即使当文件大于允许的最大值时我return
在函数中有一个,然后执行(文件实际上已上传到服务器),为什么会这样?def prepare(self)
def data_received
def post
任何帮助/提示表示赞赏。我是tornado
JS 的新手,如果问题非常基本,我很抱歉。
使用龙卷风 6.1 版,python 3.9
应用程序.py
from tornado import version as tornado_version
from tornado.ioloop import IOLoop
import tornado.web
import uuid
import os
import json
MB = 1024 * 1024
GB = 1024 * MB
MAX_STREAMED_SIZE = 1024 #20 * GB
@tornado.web.stream_request_body
class UploadHandler(tornado.web.RequestHandler):
def initialize(self):
self.bytes_read = 0
self.loaded = 0
self.data = b''
def prepare(self):
self.content_len = int(self.request.headers.get('Content-Length'))
if self.content_len > MAX_STREAMED_SIZE:
txt = "Too big file"
print(txt)
self.set_status(400)
# how do I pass this txt to an document element?
self.write(json.dumps({'error': txt}))
# eventhough I have a return here execution is continued
# in data_received() and post() functions
# Why is that?
return
def data_received(self, chunk):
self.bytes_read += len(chunk)
self.data += chunk
def post(self):
value = self.data
fname = str(uuid.uuid4())
with open(fname, 'wb') as f:
f.write(value)
data = {'filename': fname}
print(json.dumps(data))
self.write(json.dumps(data))
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def main():
handlers = [(r'/', IndexHandler), (r'/upload', UploadHandler)]
settings = dict(debug=True, template_path=os.path.dirname(__file__))
app = tornado.web.Application(handlers, **settings)
print(app)
app.listen(9999, address='localhost')
IOLoop().current().start()
if __name__ == '__main__':
print('Listening on localhost:9999')
print('Tornado ver:', tornado_version)
main()
索引.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Upload something!</title>
</head>
<body>
<h1>Upload</h1>
<form id="uploadForm">
<input type="file" name="file" id="file" />
<br />
<input type="submit" value="Upload">
</form>
<p><span id='display'></span></p>
<script>
uploadForm.onsubmit = async (e) => {
e.preventDefault();
var fileInput = document.getElementById('file');
var fileAttr = fileInput.files[0];
console.log(fileAttr);
var filename = fileInput.files[0].name;
console.log(filename);
document.getElementById('display').innerHTML =
'Uploading ' + document.getElementById("file").value;
let formData = new FormData(document.getElementById('uploadForm'));
try {
let response = await fetch(`${window.origin}/upload`, {
method: "POST",
body: formData,
});
if (!response.ok) {
console.log('error')
console.log(response.json());
// how do I update document.getElementById('display').innerHTML
// with tornado self.write when error response?
}
let result = await response.json();
console.log(result);
document.getElementById('display').innerHTML = 'Finished';
} catch(exception) {
console.log(exception);
}
};
</script>
</body>
</html>
解决方案
在prepare
返回还不够的情况下,您需要引发异常以停止处理。
所以你有两个选择:
使用提供的功能:覆盖
write_error
您RequestHandler
以创建自定义错误响应,然后raise tornado.web.HTTPError(400)
[1] 在prepare
您之后print
自己做所有事情:用于
self.set_status
设置错误状态代码,self.write
当场写出您需要的任何内容,然后raise tornado.web.Finish
短路请求的处理。
使用您的代码,您基本上只需将return
in替换prepare
为raise tornado.web.Finish()
. 显然,如果您要在多个地方执行此操作,那么使用 #1 是有意义的,但如果您现在只有脚本,那么 #2 就可以了。
推荐阅读
- javascript - 如何使用 ramda 按数组对象中的最后一项排序
- node.js - 如何在 mongodb/mongoose 中分离用户对数据库的访问
- php - 如何修复json中的意外字符错误
- java - 在同一个项目中使用多个版本划分相同的依赖项名称
- java - 在 List 中流式传输不同的 Array 元素
- git - 单个 dotnet 核心解决方案 + git repo 中的多个微服务?
- java - 与 Memoize 一起使用的番石榴供应商的 Sonarlint 违规行为
- django - 外键转换为字符域
- ruby - 在 Ruby 中禁用 OptionParser 标志的自动完成
- if-statement - Spring Reactor:发布者发出值时如何抛出异常?