js前端分片传输大文件+mongoose后端解析

发布于:2025-05-12 ⋅ 阅读:(9) ⋅ 点赞:(0)

最近一直在完善mongoose做webserver的项目,其中程序升级要通过前端传输升级包到服务器。
因为第一次写前端代码,分片传输的逻辑,网上一堆,大同小异,而且版本啊,API不一致的问题,导致头疼的很。后面废了九牛二虎之力,想出了用websocket传输二进制升级包,再另加一个消息发送文件名,也就是二进制文件和文本文件分两次发送。

function sendFile(file) {
    const reader = new FileReader();
    reader.onload = function(event) {
        const arrayBuffer = event.target.result;
        const uint8Array = new Uint8Array(arrayBuffer);
        const chunkSize = 10240;
        for (let i = 0; i < uint8Array.length; i += chunkSize) {
            const chunk = uint8Array.slice(i, i + chunkSize);
            websocket.send(chunk);
        }
     };
     reader.readAsArrayBuffer(file);
}

今天腾出时间来了,看着这个明显不合理的做法。在网上查了下,同时传输二进制和文本消息的可以用http协议中的multipart/form-data。

# 请求头 - 这个是必须的,需要指定Content-Type为multipart/form-data,指定唯一边界值
Content-Type: multipart/form-data; boundary=${Boundary}
 
# 请求体
--${Boundary}
Content-Disposition: form-data; name="name of file"
Content-Type: application/octet-stream
 
bytes of file
--${Boundary}
Content-Disposition: form-data; name="name of pdf"; filename="pdf-file.pdf"
Content-Type: application/octet-stream
 
bytes of pdf file
--${Boundary}
Content-Disposition: form-data; name="key"
Content-Type: text/plain;charset=UTF-8
 
text encoded in UTF-8
--${Boundary}--

结果发送小的文本文件貌似没啥问题,发送100多M的大文件,就死活搞不成功了,关键的是不知道咋解析带有boundary的body内容,有个mg_http_next_multipart貌似沾点边,但是没能解析成功。
只好继续百度了,结果发现好像mg_http_upload也有点沾边,但是这个函数的含义,具体用法,又没有注释,真是难啊。
突然想着可以去微软的bing搜索一下,立马就出来了mongoose的官网,里面就写了如何传输需要分片大文件的过程,具体参考mongoose手册。
哎,真是多少年了,还是犯以前在学校的错误。课本概念,例子不弄清楚,就到处去看辅导书。这会是有现成的官网例子不看,成天去看别人的二手资料,也不知道资料是基于哪个API版本。
既然如此,那就下载mongoose手册吧,这下可好了,github又打不开了,真是想干点事,太难了。
那就去gitee吧,一搜,还真有其他好人,早就把mongoose搬过来了,下载简直不要太舒服了。
一切就绪,现用例子试试分片的例子。

document.getElementById('fileMcu').addEventListener('change', function(event) {
            selectFile = event.target.files[0];
            var r = new FileReader();
            r.readAsArrayBuffer(selectFile);
            r.onload = function() {
                sendFileData(selectFile.name, new Uint8Array(r.result), 1024*1024);
            };
        });

        var sendFileData = function(name, data, chunkSize) {
            var sendChunk = function(offset) {
                var chunk = data.subarray(offset, offset + chunkSize) || '';
                var opts = {method: 'POST', body: chunk};
                var url = '/uploadMcu?offset=' + offset + '&file=' + encodeURIComponent(name);
                fetch(url, opts)
                    .then(function(res) {
                        if (res.ok && chunk.length > 0) sendChunk(offset + chunk.length);
                        return res.text();
                    });
            };
            sendChunk(0);
        };

后端C++代码接收文件时,只用一句话,
mg_http_upload(connection, httpReq, &mg_fs_posix, “.”, 999999999);
简直不要太舒服了,都不用自己拼包,自己打开文件写入。
这个时候看了下mg_http_upload的源码,里面就有获取 mg_http_get_var(&hm->query, “offset”, buf, sizeof(buf));
mg_http_get_var(&hm->query, “file”, file, sizeof(file));语句。
这个好熟悉啊,不就是上面的URL后面跟的参数吗?难怪不用自己拼包,打开文件写入呢,你按照正确的格式传输数据,mg_http_upload就能搞定所有的事。
这个周末值了,头疼的事情搞定了。从这个事情明白了,看官网手册的重要性,不得不说老外搞开源项目还是很正规的,值得我们学习。还有就是做一件事情难点很多,哪怕你搞定了最重要的80%,还有不起眼的20%照样能摧毁你,怎么样让自己的知识系统化,全面化,这样才能不断往前推进。


网站公告

今日签到

点亮在社区的每一天
去签到