正确读取多部分表单数据流(NodeJS)

Posted

技术标签:

【中文标题】正确读取多部分表单数据流(NodeJS)【英文标题】:Reading multipartform-data stream correctly (NodeJS) 【发布时间】:2020-08-18 09:17:40 【问题描述】:

我正在尝试接收可能包含各种文件和字段的多部分数据流并将文件写入目录(uWebsockets.js 服务器)。 我有这个代码:

    let boundary = null;
    let fields = [];
    let streams = [];
    let keep = false;
    res.onData((chunk, isLast) => 
        const buff = Buffer.concat([Buffer.from(chunk)]).toString('binary').split('\r\n');
        if (!boundary) 
            boundary = buff[0];
        
        for (let i = 0; i < buff.length; i++) 

            const line = buff[i];
            if (i > 0 && i < buff.length - 1 && line == '') 
                keep = true;
                continue;
            
            if (line == boundary || line == boundary + '--') 
                keep = false;
                if (streams[fields.length - 1]) 
                    streams[fields.length - 1].end();
                
            
            if (line == boundary) 
                fields[fields.length] = ;
            

            if (line.includes('Content-Disposition')) 
                if (line.includes('filename="')) 
                    fields[fields.length - 1].filename = getFilename(line);
                    fields[fields.length - 1].type = 'file';
                    fields[fields.length - 1].path = path.resolve(options.uploadPath + fields[fields.length - 1].filename);
                    streams[fields.length - 1] = fs.createWriteStream(
                        path.resolve(options.uploadPath + fields[fields.length - 1].filename)
                    );
                 else 
                    fields[fields.length - 1].type = 'field';
                
                fields[fields.length - 1].name = getField(line);
            
            if (line.includes('Content-Type')) 
                fields[fields.length - 1].contentType = line.split('Content-Type: ')[1];
            

            if (keep == true) 
                if (fields[fields.length - 1].filename) 
                    streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));
                 else 
                    fields[fields.length - 1].value += line;
                
            
        

        if (isLast) 
            console.log(fields);
        
    );

它可以正常工作,只是上传的图像已损坏并被随机剪切(每张图像都不相同,有些完全损坏,有些则完全正常)。 有人能指出它有什么问题吗?

提前致谢:)

【问题讨论】:

你看过 Mutler:npmjs.com/package/multerForm-data:npmjs.com/package/form-data我创建了一个使用multipartform-data提交的节点端点。 如果你愿意,我可以分享代码。至于您的代码,我建议您尝试手动执行。 @mmason33 是的,如果你能和我分享,那就太好了!谢谢 @mmason33 Mutler 是一个 Express 中间件,对吗?如果是这样,那么它将无法工作,因为我没有使用 Express。我正在使用 uWebsocket.js 作为 Express 的替代品。 【参考方案1】:

同样的情况,我正在使用 uwebsocket.js 上传 mp4 文件,我尝试使用您的代码上传 mp4,它已上传但无法播放。然后我尝试将原始文件与上传的文件进行比较,文件大小略有变化。

然后我在你的代码中意识到:

streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));

当被“\r\n”分割时,数组的最后一个不应有“\r\n” 比我在下面添加一些条件:

if (i==buff.length-1)
   streams[streams.length - 1].write(Buffer.from(line, 'binary'));
else 
   if (i+1<buff.length) 
      if (buff[i+1]==boundary + '--')
         streams[streams.length - 1].write(Buffer.from(line, 'binary'));
      else
         streams[streams.length - 1].write(Buffer.from(line + "\r\n", 'binary'));
   

现在我上传的 mp4 播放良好。

谢谢....

对不起我的英语不好

【讨论】:

【参考方案2】:

概率问题是最大长度。在 uwebsocket.js 上更改此值。 最好的方法是上传文件的表单数据。

改变这个:

maxPayloadLength: 512

更多详情:https://unetworking.github.io/uWebSockets.js/generated/interfaces/websocketbehavior.html#maxpayloadlength

【讨论】:

那是 websocket 有效载荷。我使用 uWebsocket 作为 Express 的替代品。 顺便说一句,如果我连接所有块然后写入所有文件,那么一切正常。唯一的问题是它不适用于非常大的文件。这就是我尝试直接从流中写入文件的原因。 您的目标是让某人上传文件并让其他人立即得到通知吗?如果您使用表单数据和 Web 套接字是否会向您发送一个密钥(redis 上的临时或类似的东西)(例如:mysite/upload/:key)。***.com/a/11081396/13351032 不,即使 uWebsocket.js 的名称中有“websocket”,它也是一个 http 服务器(如 express)。我正在尝试读取多部分表单流并写入上传的文件。我在这段代码中没有使用 Websocket。【参考方案3】:

你试过formidable吗? 我用它来解析我的多部分数据流。

【讨论】:

它可以从流块中解析吗?或者它需要流完成然后解析它? 既然还没有人找到解决办法,我需要给悬赏,那我就给你(也是因为你积分不多)。 是的,您可以从流块中解析。 它不直接从流块中写入。它连接块然后解析。所以这不是我需要的。 github.com/node-formidable/formidable/blob/…

以上是关于正确读取多部分表单数据流(NodeJS)的主要内容,如果未能解决你的问题,请参考以下文章

如何在烧瓶中读取多部分/表单数据[重复]

处理多部分/表单数据请求失败。读取超时

无法将多部分表单数据从 React 正确发送到 Express Js

多部分/表单数据请求失败。直播意外结束

WebAPI 无法解析多部分/表单数据帖子

使用 PHP 手动解析原始多部分/表单数据数据