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

向Express服务器上传文件时仅视频出现TypeError/NetworkError异常

解决重复上传视频文件时的NetworkError问题

问题根源

当检测到视频文件已存在并返回409状态码后,服务器没有终止对上传文件流的处理。视频文件体积较大,浏览器仍在持续上传数据,但服务器已经发送了响应,导致连接被强制中断,最终触发NetworkError。而图片文件体积小,可能在服务器返回响应前就完成了数据上传,因此不会出现该问题。

解决方案

1. 服务器端:终止文件流并正确结束响应

在检测到文件已存在时,不仅要返回409状态码,还要手动终止file流的读取,避免后续数据继续传输,同时确保响应完全结束。另外,将res.redirect('back')改为返回明确的状态码,避免fetch请求处理重定向的异常。

修改后的服务器代码:

var express = require("express");
var busboy = require('connect-busboy');
var cors = require('cors');
var fs = require('fs');
var path = require('path');

var app = express();
app.use(busboy());
app.use(cors());
app.use(express.static(path.join(__dirname, 'public')));

app.route('/upload')
    .post(function (req, res, next) {
        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename) {
            const filePath = path.join(__dirname, 'public/uploaded', filename.filename);
            if (fs.existsSync(filePath)) {
                // 终止文件流读取,避免内存泄漏
                file.resume();
                return res.sendStatus(409);
            } else {
                console.log("Uploading: " + filename.filename);
                const fstream = fs.createWriteStream(filePath, {flags: "w+"});
                file.pipe(fstream);
                fstream.on('close', function () {    
                    console.log("Upload Finished of " + filename.filename);              
                    res.sendStatus(200);
                });
                // 捕获文件写入错误
                fstream.on('error', function(err) {
                    console.error('文件写入错误:', err);
                    res.sendStatus(500);
                });
            }
        });
        // 捕获Busboy处理错误
        req.busboy.on('error', function(err) {
            console.error('Busboy错误:', err);
            res.sendStatus(500);
        });
    });

var server = app.listen(4200, function() {
    console.log('Listening on port %d', server.address().port);
});

2. 前端:完善fetch的错误处理

fetch API不会对HTTP错误状态码(如409)触发reject,需要手动检查响应状态,并添加网络错误的捕获逻辑:

修改后的前端index.js代码:

document.getElementById("upload").onchange = function() {
    let photo = document.getElementById("upload").files[0];
    let formData = new FormData();
             
    formData.append("photo", photo);
    fetch("/upload", {method: "POST", body: formData})
        .then(response => {
            if (response.status === 409) {
                alert("文件已存在");
            } else if (!response.ok) {
                throw new Error(`请求失败: ${response.status}`);
            } else {
                alert("上传成功");
            }
        })
        .catch(error => {
            console.error('上传出错:', error);
            alert("上传失败,请重试");
        });
}

额外优化建议

  • 使用异步IO替代同步IO,避免阻塞服务器线程:
    // 替换原有的fs.existsSync判断
    try {
        await fs.promises.access(filePath, fs.constants.F_OK);
        file.resume();
        return res.sendStatus(409);
    } catch {
        // 文件不存在,执行上传逻辑
    }
    
  • 给上传按钮添加loading状态,防止用户重复提交。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:32:17