前端大文件上传以及以外情况的解决

现在大部分的应用都会有上传文件的功能,小的可以直接正常直接上传,但是如果遇到大型文件需要上传那会面临着很多问题比如网络中断等问题会造成上传失败,下面我将针对大文件上传出一个解决方案,有什么问题麻烦各位指出。

一、前端实现步骤

1.文件选择

用户通过文件选择控件选择一个或多个大文件。

javascript 复制代码
<input type="file" id="fileInput" multiple>

2.文件校验

检查文件的大小和类型是否符合要求

javascript 复制代码
const fileInput = document.getElementById('fileInput');  
fileInput.onchange = (e) => {  
    const files = e.target.files;  
    for (let file of files) {  
        if (file.size > MAX_FILE_SIZE) {  
            alert('文件过大,请选择较小的文件');  
            return;  
        }  
        if (!VALID_FILE_TYPES.includes(file.type)) {  
            alert('不支持的文件类型');  
            return;  
        }  
    }  
};  

const MAX_FILE_SIZE =20 * 1024 * 1024; // 20MB  
const VALID_FILE_TYPES = ['image/jpeg', 'image/png', 'application/pdf'];//可以自行添加文件类型

3.文件分片

使用Blob对象的slice方法将文件分割成多个小块(分片)。

javascript 复制代码
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB  

function chunkFile(file, chunkSize) {  
    const chunks = [];  
    for (let start = 0; start < file.size; start += chunkSize) {  
        const end = Math.min(start + chunkSize, file.size);  
        chunks.push(file.slice(start, end));  
    }  
    return chunks;  
}

4.生成文件哈希

为文件生成一个唯一的哈希值(如MD5),用于标识文件和验证文件的完整性。

javascript 复制代码
import SparkMD5 from 'spark-md5';  

function getFileHash(file) {  
    return new Promise((resolve, reject) => {  
        const chunkSize = 2048 * 1024; // 2MB  
        const chunks = Math.ceil(file.size / chunkSize);  
        let currentChunk = 0;  
        const spark = new SparkMD5.ArrayBuffer();  
        const fileReader = new FileReader();  

        fileReader.onload = (e) => {  
            const chunk = e.target.result;  
            spark.append(chunk);  
            currentChunk++;  

            if (currentChunk < chunks) {  
                loadNext();  
            } else {  
                resolve(spark.end());  
            }  
        };  

        fileReader.onerror = (e) => {  
            reject('Error reading file: ' + e.message);  
        };  

        function loadNext() {  
            const start = currentChunk * chunkSize;  
            const end = start + chunkSize >= file.size ? file.size : start + chunkSize;  
            fileReader.readAsArrayBuffer(file.slice(start, end));  
        }  

        loadNext();  
    });  
}

5上传分片

使用FormData对象构建上传请求,将分片逐个上传到服务器。可以使用并发请求来提高上传速度

javascript 复制代码
async function uploadChunks(chunks, fileHash, fileName) {  
    const promises = chunks.map((chunk, index) => {  
        const formData = new FormData();  
        formData.append('file', chunk);  
        formData.append('index', index);  
        formData.append('fileHash', fileHash);  
        formData.append('fileName', fileName);  

        return fetch('/upload', {  
            method: 'POST',  
            body: formData,  
        }).then(response => response.json());  
    });  

    return Promise.all(promises);  
}

6.合并分片

当所有分片上传完成后,通知服务器合并分片。

javascript 复制代码
async function mergeChunks(fileHash, fileName, totalChunks) {  
    const response = await fetch('/merge', {  
        method: 'POST',  
        headers: {  
            'Content-Type': 'application/json',  
        },  
        body: JSON.stringify({ fileHash, fileName, totalChunks }),  
    });  

    return response.json();  
}

7.错误处理

处理上传过程中的各种错误,如网络错误、文件校验错误等。

javascript 复制代码
async function uploadFile(file) {  
    try {  
        const fileHash = await getFileHash(file);  
        const chunks = chunkFile(file, CHUNK_SIZE);  
        const fileName = file.name;  
        const totalChunks = chunks.length;  

        const uploadResults = await uploadChunks(chunks, fileHash, fileName);  
        const mergeResult = await mergeChunks(fileHash, fileName, totalChunks);  

        if (mergeResult.success) {  
            alert('文件上传成功');  
        } else {  
            alert('文件合并失败:' + mergeResult.message);  
        }  
    } catch (error) {  
        alert('文件上传失败:' + error.message);  
    }  
}  

fileInput.onchange = (e) => {  
    const files = e.target.files;  
    for (let file of files) {  
        uploadFile(file);  
    }  
};

二、后端实现步骤

  1. 接收分片

    后端接收分片并存储到临时位置

javascript 复制代码
// 示例:Node.js + Express  
const express = require('express');  
const multer = require('multer');  
const fs = require('fs');  
const path = require('path');  

const app = express();  
const upload = multer({ dest: 'uploads/temp' });  

app.post('/upload', upload.single('file'), (req, res) => {  
    const { index, fileHash, fileName } = req.body;  
    const chunkPath = path.join(__dirname, 'uploads/temp', `${fileHash}-${index}`);  
    fs.renameSync(req.file.path, chunkPath);  
    res.status(200).send({ success: true });  
});

2.合并分片

后端根据文件哈希和分片索引合并分片。

javascript 复制代码
app.post('/merge', (req, res) => {  
    const { fileHash, fileName, totalChunks } = req.body;  
    const filePath = path.join(__dirname, 'uploads', fileName);  
    const writeStream = fs.createWriteStream(filePath);  

    for (let i = 0; i < totalChunks; i++) {  
        const chunkPath = path.join(__dirname, 'uploads/temp', `${fileHash}-${i}`);  
        const data = fs.readFileSync(chunkPath);  
        writeStream.write(data);  
        fs.unlinkSync(chunkPath); // 删除临时分片文件  
    }  

    writeStream.end();  
    res.status(200).send({ success: true });  
});

3.错误处理

处理接收和合并过程中的各种错误,如文件校验错误、存储错误等。

javascript 复制代码
// 示例:错误处理逻辑  
app.use((err, req, res, next) => {  
    console.error(err.stack);  
    res.status(500).send('服务器内部错误');  
});

三、总结

通过以上步骤和技术实现,你可以实现一个前端大文件上传的功能。前端负责文件选择、校验、分片、哈希生成、上传和错误处理;后端负责接收分片、存储和合并分片。不过还有一些别的特殊情况要处理比如取消上传,上传进度展示等

相关推荐
Monly214 分钟前
JS:JSON操作
前端·javascript·json
小何学计算机1 小时前
Nginx 配置基于主机名的 Web 服务器
服务器·前端·nginx
web_code1 小时前
vite依赖预构建(源码分析)
前端·面试·vite
觉醒法师1 小时前
HarmonyOS开发 - 本地持久化之实现LocalStorage支持多实例
前端·javascript·华为·typescript·harmonyos
小何学计算机2 小时前
Nginx 配置基于IP 地址的 Web 服务器
前端·tcp/ip·nginx
w风雨无阻w2 小时前
Vue3 学习笔记(十一)Vue生命周期
javascript·vue.js·前端框架·vue3
清清ww2 小时前
【vue】13.深入理解递归组件
前端·javascript·vue.js
清清ww2 小时前
【vue】09.computer和watch的使用
前端·javascript·vue.js
Gnevergiveup2 小时前
2024网鼎杯青龙组Web+Misc部分WP
开发语言·前端·python
你不讲 wood2 小时前
使用 Axios 上传大文件分片上传
开发语言·前端·javascript·node.js·html·html5