返回

巧用File API:实现大文件断点续传

后端

在处理大数据或大文件时,直接一次性将文件上传至服务器可能会因网络状况不佳而失败,甚至导致用户数据丢失。为了解决这个问题,可以采用大文件分块上传和断点续传技术。这种方法允许将一个大的文件分割成多个小的块,分别进行传输,如果某个块在传输过程中出现问题,则可以从断点处重新开始。

使用 File API 实现大文件分块上传

文件分块原理

File API 提供了 slice() 方法,可以用来创建文件的一部分。结合 FileReader 的读取功能,可以实现对大文件的分割和逐段处理。每次只将一部分内容传至服务器,这样即使传输失败,也可以从失败的位置开始恢复。

示例代码:使用 slice 分割文件
function chunkFile(file, chunkSize) {
    let chunks = [];
    for (let i = 0; i < file.size; i += chunkSize) {
        chunks.push(file.slice(i, Math.min(file.size, i + chunkSize)));
    }
    return chunks;
}

这里定义了一个函数 chunkFile,它接收文件对象和每个块的大小作为参数,返回一个数组,包含文件的所有分块。

断点续传机制

为了实现断点续传功能,上传时需要跟踪已上传的内容,并在请求中传递这些信息。可以通过 HTTP 的 Range 头来指定已经传输的部分,在服务器端进行处理以识别和恢复未完成的上传任务。

示例代码:客户端发送分块
async function uploadChunk(file, chunk, index) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", "/upload");
    xhr.setRequestHeader('Content-Type', file.type);
    
    // 添加断点续传头部信息
    xhr.setRequestHeader('Range', `bytes=${index * chunk.length}-${(index + 1) * chunk.length - 1}/${file.size}`);
    xhr.send(chunk);

    return new Promise((resolve, reject) => {
        xhr.onload = function () { resolve(xhr.responseText); };
        xhr.onerror = function () { reject(xhr.statusText); };
    });
}

此代码段展示了如何上传一个文件块,并设置适当的头部信息以支持断点续传。每个请求都包含了该块的范围和文件总大小。

服务器端处理

在服务器端,必须能够识别并处理这些部分上传的信息。根据客户端提供的 Range 头来定位文件的位置,并将新接收的数据写入相应位置。

示例代码:服务端处理分段数据(Node.js)
app.post('/upload', (req, res) => {
    const range = req.headers.range;
    if (!range) {
        return res.status(400).send('Range header required.');
    }
    
    // 假设我们有一个文件存储位置和读写逻辑
    const [start] = range.replace(/bytes=/, "").split("-").map(Number);
    fs.appendFileSync(fileName, req.body, { flag: 'a' });
    
    res.status(200).send('Chunk received.');
});

这段代码展示了如何在 Node.js 环境下处理上传请求,根据客户端提供的 Range 头来确定数据的写入位置。

安全与注意事项

  • 文件校验:确保服务器接收到的数据是完整的且未被篡改。可以使用哈希值进行验证。
  • 并发控制:如果一个用户多次尝试上传同一文件的不同部分,要避免出现并发冲突或覆盖问题。
  • 存储管理:管理好临时文件的存储和清理机制,防止占用过多服务器资源。

结语

通过本文介绍的方法,可以有效提升大文件传输的成功率,并大幅减少由于网络不稳定导致的数据重传。结合客户端和服务端的技术实现,断点续传技术在实际应用中发挥了重要作用,尤其适用于大数据上传场景。