Flutter http.MultipartRequest上传MIDI文件后头部异常求助
问题描述
开发项目网站时,用户通过Flutter上传MIDI文件至后端处理后返回,但上传后的文件头部出现随机字符,导致Python的mido库无法识别为有效MIDI文件。FTP上传的文件正常,Flutter上传的文件头部异常,报错提示找不到MTrk头。
同一文件FTP与Flutter上传后的头部对比:
Mido报错信息
b'\xbf\xbdMT' Traceback (most recent call last): File "generate.py", line 141, in <module> midi_file = MidiFile(MIDI_PATH) File "/usr/local/lib/python3.8/dist-packages/miditoolkit/midi/parser.py", line 31, in __init__ mido_obj = mido.MidiFile(filename=filename, clip=clip, charset=charset) File "/usr/local/lib/python3.8/dist-packages/mido/midifiles/midifiles.py", line 324, in __init__ self._load(file) File "/usr/local/lib/python3.8/dist-packages/mido/midifiles/midifiles.py", line 359, in _load self.tracks.append(read_track(infile, File "/usr/local/lib/python3.8/dist-packages/mido/midifiles/midifiles.py", line 181, in read_track raise IOError('no MTrk header at start of track') OSError: no MTrk header at start of track
Flutter上传代码
void _pickFile() async { final result = await FilePicker.platform.pickFiles(allowMultiple: false); if (result == null) { return; } setState(() { _isLoading = true; }); if (result.files.first.bytes != null) { final request = http.MultipartRequest('POST', Uri.parse(genAPI)); request.files.add(await http.MultipartFile.fromBytes( 'file', result.files.first.bytes!, contentType: MediaType('audio', 'midi'))); print("files"); print(request.files); try { final response = await request.send(); if (response.statusCode == 200) { // Do something with the response print("response"); print(response); setState(() { _isDownloadable = true; _file = result.files.first; }); } else { // Handle error response print(response); } } catch (e) { // Handle network errors print(e); } } else { print('ERROR'); } setState(() { _isLoading = false; }); }
Node.js接收代码
app.post('/process-file', upload.single('file'), (req, res) => { // Check if req.file is defined if (!req.body.file) { console.log("NO FILE IN REQUEST"); return res.status(400).send('No file uploaded'); } // Get the uploaded file from the request object const file = req.body.file; const fpath = Date.now() + '.mid'; //file.originalname; // Write file to disk fs.writeFileSync('uploads/orig_' + fpath, file, (err) => { if (err) { console.error(err); return res.status(500).send('Error writing file to disk'); } else { console.error('file loaded successfully'); } }); });
问题原因与解决方法
核心问题
问题出在Node.js后端的文件接收逻辑:使用upload.single('file')(multer中间件)后,错误地从req.body.file读取文件内容,而非req.file。req.body中的内容是经过编码的文本格式,直接写入磁盘会导致文件头部出现乱码,破坏MIDI文件的二进制结构。
修复步骤
修正Node.js后端逻辑:
将读取文件的来源改为req.file,并使用req.file.buffer获取原始二进制数据写入磁盘。同时fs.writeFileSync是同步方法,无需传入回调函数,调整后的代码如下:app.post('/process-file', upload.single('file'), (req, res) => { // 检查是否存在上传文件 if (!req.file) { console.log("NO FILE IN REQUEST"); return res.status(400).send('No file uploaded'); } const fpath = Date.now() + '.mid'; const filePath = 'uploads/orig_' + fpath; try { // 写入原始二进制数据 fs.writeFileSync(filePath, req.file.buffer); console.log('file loaded successfully'); res.status(200).send('File uploaded and saved'); } catch (err) { console.error(err); return res.status(500).send('Error writing file to disk'); } });Flutter端验证:
Flutter的http.MultipartRequest和MultipartFile.fromBytes是正确的二进制上传方式,无需修改。确保genAPI指向正确的后端接口即可。
补充说明
- 使用multer中间件时,上传的文件信息会被解析到
req.file中,包含buffer(原始二进制数据)、originalname(原文件名)等字段;req.body仅用于接收普通表单字段。 - MIDI是二进制格式,必须保证上传、传输、存储全程使用二进制处理,任何文本编码/解码操作都会破坏文件结构。
内容的提问来源于stack exchange,提问作者Marwan Sabry
相关产品推荐
相关产品推荐

