You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tornado stream_request_body场景自定义错误返回及执行逻辑问题

问题解决办法

一、Tornado 端 prepare 返回后仍执行 data_received/post 的问题

原因

你使用了@tornado.web.stream_request_body装饰器开启流式请求体接收,prepare方法的return只会结束当前方法的执行,不会主动终止整个请求处理流程,Tornado仍然会持续接收客户端上传的请求体数据,触发data_received回调,最后执行post方法。

解决办法

在错误分支写完响应内容后,调用self.finish()显式终止请求:

def prepare(self):
    self.content_len = int(self.request.headers.get('Content-Length'))
    if self.content_len > MAX_STREAMED_SIZE:
        txt = "Too big file"
        self.set_status(400)
        # 明确返回JSON格式头,方便前端解析
        self.set_header('Content-Type', 'application/json')
        self.write(json.dumps({'error': txt}))
        # 显式终止请求,不会再执行后续的data_received和post
        self.finish()
        return 

二、JS端 Body has already been consumed 报错+错误提示显示问题

原因

fetch返回的Response对象的body是只能读取一次的流,你在!response.ok分支调用了一次response.json(),后续逻辑又调用了一次,第二次读取时body已经被消费完了就会报错。同时你调用response.json()时没加await,所以控制台会打印pending状态的Promise。

解决办法

只读取一次响应体,错误分支拿到错误信息后直接更新页面元素并终止逻辑:
修改后的JS逻辑如下:

uploadForm.onsubmit = async (e) => {
    e.preventDefault();
    var fileInput = document.getElementById('file');
    var fileAttr = fileInput.files[0];
    var filename = fileAttr.name;

    const displayEl = document.getElementById('display');
    displayEl.innerHTML = 'Uploading ' + filename;

    let formData = new FormData(document.getElementById('uploadForm'));
    try {
        let response = await fetch(`${window.origin}/upload`, {
            method: "POST",
            body: formData,
        });
        // 只读取一次响应体
        let result = await response.json();
        if (!response.ok) {
            // 直接用返回的错误信息更新页面元素
            displayEl.innerHTML = result.error;
            // 终止后续成功逻辑
            return;
        }
        console.log(result);
        displayEl.innerHTML = '上传完成';
    } catch(exception) {
        console.log(exception);
        displayEl.innerHTML = '上传发生错误,请重试';
    } 
};

额外优化建议

  • 可以在前端先做一次文件大小校验,不用等到请求发往服务端再拦截,减少不必要的带宽消耗:拿到文件对象后判断fileAttr.size > MAX_SIZE就直接提示错误,不发起fetch请求。
  • 服务端保存文件的路径最好指定固定目录,避免生成的文件散落在项目根目录。

内容的提问来源于stack exchange,提问作者jonas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 12:00:05