>웹 프론트엔드 >JS 튜토리얼 >Node.js에서 멀티파트 업로드를 구현하는 방법은 무엇입니까? 방법 소개

Node.js에서 멀티파트 업로드를 구현하는 방법은 무엇입니까? 방법 소개

青灯夜游
青灯夜游앞으로
2022-07-29 20:22:171805검색

Node멀티파트 업로드를 구현하는 방법은 무엇입니까? 다음 글에서는 Node.js에서 멀티파트 업로드를 구현하는 방법을 소개하겠습니다. 도움이 되길 바랍니다.

Node.js에서 멀티파트 업로드를 구현하는 방법은 무엇입니까? 방법 소개

대용량 파일을 업로드하면 시간도 많이 소모되고, 중간에 업로드가 실패할 수도 있습니다. 이때 이 문제를 해결하려면 프런트엔드와 백엔드의 협력이 필요합니다.

해결 단계:

  • 파일 조각화를 통해 각 요청에 소요되는 시간을 줄입니다. 요청이 실패하면 처음부터 시작하는 대신 별도로 업로드할 수 있습니다.

  • 파일 조각을 병합하도록 서버에 알립니다.

  • 브라우저 메모리 오버플로를 방지하기 위해 동시 요청 수를 제어하세요

  • 네트워크 또는 기타 이유로 요청이 실패하면 요청을 다시 보냅니다

파일 조각화 및 병합

JavaScript에서는 FIle 개체 'Blob' 개체의 하위 클래스입니다. 이 개체에는 다음과 같이 바이너리 파일을 분할할 수 있는 중요한 메서드 슬라이스가 포함되어 있습니다. 많은 양의 요청이 발생하고 브라우저는 짧은 시간 내에 많은 수의 요청을 시작하므로 메모리가 고갈될 수 있으므로 동시성 제어가 필요합니다.

여기서 Promise.race() 메서드를 결합하여 동시 요청 수를 제어하고 브라우저 메모리 오버플로를 방지합니다.
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.24.0/axios.min.js"></script>
</head>
<body>
    <input type="file" multiple="multiple" id="fileInput" />
    <button onclick="SliceUpload()">上传</button>  
    <script>
        function SliceUpload() {
            const file = document.getElementById('fileInput').files[0]
            if (!file) return

            // 文件分片
            let size = 1024 * 50; //50KB 50KB Section size
            let fileChunks = [];
            let index = 0;        //Section num
            for (let cur = 0; cur < file.size; cur += size) {
                fileChunks.push({
                    hash: index++,
                    chunk: file.slice(cur, cur + size),
                });
            }

            // 上传分片
            const uploadList = fileChunks.map((item, index) => {
                let formData = new FormData();
                formData.append("filename", file.name);
                formData.append("hash", item.hash);
                formData.append("chunk", item.chunk);
                return axios({
                    method: "post",
                    url: "/upload",
                    data: formData,
                });
            });
            await Promise.all(uploadList);

            // 所有分片上传完成,通知服务器合并分片
            await axios({
                method: "get",
                url: "/merge",
                params: {
                    filename: file.name,
                },
            });
            console.log("Upload to complete");
        }
    </script>
</body>
</html>

코드를 재사용 가능하게 만들기

// 加入并发控制
async function SliceUpload() {
    const file = document.getElementById('fileInput').files[0]
    if (!file) return

    // 文件分片
    let size = 1024 * 50; //50KB 50KB Section size
    let fileChunks = [];
    let index = 0;        //Section num
    for (let cur = 0; cur < file.size; cur += size) {
        fileChunks.push({
            hash: index++,
            chunk: file.slice(cur, cur + size),
        });
    }

    let pool = []; //Concurrent pool
    let max = 3; //Maximum concurrency
    for (let i = 0; i < fileChunks.length; i++) {
        let item = fileChunks[i];
        let formData = new FormData();
        formData.append("filename", file.name);
        formData.append("hash", item.hash);
        formData.append("chunk", item.chunk);

        // 上传分片
        let task = axios({
            method: "post",
            url: "/upload",
            data: formData,
        });
        task.then(() => {
        // 从并发池中移除已经完成的请求
        let index = pool.findIndex((t) => t === task);
            pool.splice(index);
        });

        // 把请求放入并发池中,如果已经达到最大并发量
        pool.push(task);
        if (pool.length === max) {
            //All requests are requested complete
            await Promise.race(pool);
        }
    }

    // 所有分片上传完成,通知服务器合并分片
    await axios({
        method: "get",
        url: "/merge",
        params: {
            filename: file.name,
        },
    });
    console.log("Upload to complete");
}

서버 인터페이스 구현

function SliceUpload() {
    const file = document.getElementById('fileInput').files[0]
    if (!file) return

    // 文件分片
    let size = 1024 * 50; // 分片大小设置
    let fileChunks = [];
    let index = 0;        // 分片序号
    for (let cur = 0; cur < file.size; cur += size) {
        fileChunks.push({
            hash: index++,
            chunk: file.slice(cur, cur + size),
        });
    }

    const uploadFileChunks = async function(list){
        if(list.length === 0){
            // 所有分片上传完成,通知如无
            await axios({
                method: &#39;get&#39;,
                url: &#39;/merge&#39;,
                params: {
                    filename: file.name
                }
            });
            console.log(&#39;Upload to complete&#39;)
            return
        }

        let pool = []       // 并发池
        let max = 3         // 最大并发数
        let finish = 0      // 完成数量
        let failList = []   // 失败列表
        for(let i=0;i<list.length;i++){
            let item = list[i]
            let formData = new FormData()
            formData.append(&#39;filename&#39;, file.name)
            formData.append(&#39;hash&#39;, item.hash)
            formData.append(&#39;chunk&#39;, item.chunk)
            
            let task = axios({
                method: &#39;post&#39;,
                url: &#39;/upload&#39;,
                data: formData
            })

            task.then((data)=>{
                // 从并发池中移除已经完成的请求
                let index = pool.findIndex(t=> t===task)
                pool.splice(index)
            }).catch(()=>{
                failList.push(item)
            }).finally(()=>{
                finish++
                // 如果有失败的重新上传
                if(finish===list.length){
                    uploadFileChunks(failList)
                }
            })
            pool.push(task)
            if(pool.length === max){
                await Promise.race(pool)
            }
        }
    }

    uploadFileChunks(fileChunks)
}
더 많은 노드 관련 지식을 보려면

nodejs 튜토리얼

을 방문하세요!

위 내용은 Node.js에서 멀티파트 업로드를 구현하는 방법은 무엇입니까? 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제