文件分片和断点虚传

前端代码

要优化前端的文件分片上传代码,我们可以考虑以下几点:

  1. 异步上传与并发控制:上传分片时使用异步请求,并控制同时上传的分片数量,避免同时发送过多请求导致浏览器或服务器压力过大。

  2. 上传进度显示:向用户显示每个分片的上传进度和总体进度。

  3. 断点续传:在上传之前检查哪些分片已经上传过,只上传未完成的分片。

  4. 错误处理与重试机制:对于上传失败的分片,实现自动重试逻辑。

以下是优化后的前端代码示例:

HTML 部分
html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>File Upload</title>
</head>
<body>
    <input type="file" id="fileInput">
    <button onclick="uploadFile()">Upload</button>
    <div id="uploadStatus"></div>
    <progress id="uploadProgress" value="0" max="100"></progress>
</body>
</html>
JavaScript 部分
javascript 复制代码
const MAX_CONCURRENT_UPLOADS = 5;  // 最大并发上传数
let concurrentUploads = 0;        // 当前并发上传数
let fileChunksQueue = [];         // 待上传的文件分片队列

function uploadFile() {
    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];
    var chunkSize = 1024 * 1024; // 分片大小,这里设置为 1MB
    var totalChunks = Math.ceil(file.size / chunkSize);

    // 初始化分片队列
    for (let i = 0; i < totalChunks; i++) {
        let start = i * chunkSize;
        let end = Math.min(file.size, start + chunkSize);
        let chunk = file.slice(start, end);

        fileChunksQueue.push({ chunk, chunkNumber: i + 1, totalChunks, fileName: file.name });
    }

    // 开始上传
    startUploads();
}

function startUploads() {
    while (concurrentUploads < MAX_CONCURRENT_UPLOADS && fileChunksQueue.length > 0) {
        const chunkData = fileChunksQueue.shift();
        uploadChunk(chunkData);
        concurrentUploads++;
    }
}

function uploadChunk({ chunk, chunkNumber, totalChunks, fileName }) {
    var formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkNumber', chunkNumber);
    formData.append('totalChunks', totalChunks);
    formData.append('fileId', fileName);

    fetch('http://localhost:8080/file/upload', {
        method: 'POST',
        body: formData
    })
    .then(response => response.text())
    .then(data => {
        concurrentUploads--;
        updateUploadStatus(chunkNumber, totalChunks);
        startUploads(); // 继续上传下一个分片
    })
    .catch(error => {
        console.error('Error:', error);
        fileChunksQueue.push({ chunk, chunkNumber, totalChunks, fileName }); // 重试
        concurrentUploads--;
        startUploads();
    });
}

function updateUploadStatus(chunkNumber, totalChunks) {
    let uploadedChunks = chunkNumber;
    let progress = (uploadedChunks / totalChunks) * 100;
    document.getElementById('uploadProgress').value = progress;
    document.getElementById('uploadStatus').innerHTML = `Uploaded ${uploadedChunks} of ${totalChunks} chunks (${progress.toFixed(2)}%)`;
}

优化点说明

  • 并发控制 :通过 MAX_CONCURRENT_UPLOADS 控制同时上传的分片数量。
  • 上传队列 :使用 fileChunksQueue 管理待上传的分片队列。
  • 进度显示 :使用 HTML progress 元素显示上传进度。
  • 错误处理与重试:上传失败的分片会被重新放回队列中等待重试。

这种优化可以提高上传效率,同时提供更好的用户体验。还可以根据需要进一步增加例如上传失败后的最大重试次数等更复杂的逻辑。

后端代码

为了优化 Spring Boot 后端代码以更好地支持文件分片上传和断点续传,我们可以考虑以下几个方面:

  1. 增加断点续传支持:提供一个接口来检查特定文件的已上传分片。

  2. 优化文件存储:使用更高效的方式来存储和访问分片。

  3. 增强错误处理:确保在读写操作中适当处理异常。

  4. 验证分片完整性:在接收到分片时验证其完整性,如校验分片大小或内容。

  5. 日志记录:记录重要操作,帮助调试和监控上传过程。

示例代码

这是一个优化后的 Spring Boot 控制器实现示例:

java 复制代码
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.BitSet;

@RestController
@RequestMapping("/file")
public class FileUploadController {

    private final String UPLOAD_DIR = "/path/to/upload/dir/";

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFileChunk(
            @RequestParam("file") MultipartFile file,
            @RequestParam("chunkNumber") int chunkNumber,
            @RequestParam("totalChunks") int totalChunks,
            @RequestParam("fileId") String fileId) {

        try {
            Path chunkFile = Paths.get(UPLOAD_DIR + fileId + "_" + chunkNumber);
            Files.write(chunkFile, file.getBytes());

            return ResponseEntity.ok("Chunk uploaded successfully");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body("Error uploading chunk");
        }
    }

    @GetMapping("/checkUploadedChunks")
    public ResponseEntity<BitSet> checkUploadedChunks(@RequestParam("fileId") String fileId,
                                                      @RequestParam("totalChunks") int totalChunks) {
        BitSet uploadedChunks = new BitSet(totalChunks);
        for (int i = 1; i <= totalChunks; i++) {
            if (Files.exists(Paths.get(UPLOAD_DIR + fileId + "_" + i))) {
                uploadedChunks.set(i - 1);
            }
        }
        return ResponseEntity.ok(uploadedChunks);
    }

    @PostMapping("/mergeChunks")
    public ResponseEntity<String> mergeChunks(@RequestParam("fileId") String fileId,
                                              @RequestParam("totalChunks") int totalChunks) {
        try {
            mergeFileChunks(fileId, totalChunks);
            return ResponseEntity.ok("File merged successfully");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body("Error merging chunks");
        }
    }

    private void mergeFileChunks(String fileId, int totalChunks) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(UPLOAD_DIR + fileId);
             BufferedOutputStream mergingStream = new BufferedOutputStream(fos)) {
            for (int i = 1; i <= totalChunks; i++) {
                Path chunkFile = Paths.get(UPLOAD_DIR + fileId + "_" + i);
                Files.copy(chunkFile, mergingStream);
                Files.delete(chunkFile);
            }
        }
    }
}

优化点说明

  • 断点续传接口checkUploadedChunks 接口允许客户端查询特定文件的已上传分片。
  • 分片合并接口mergeChunks 接口用于合并所有上传的分片。
  • 错误处理和日志记录:在关键操作中加入了异常捕获和日志记录。

这些优化有助于提高后端处理的效率和可靠性,并支持更复杂的上传场景。根据实际需求,可以进一步增加如上传权限检查、分片完整性校验等功能。

相关推荐
m0_748235249 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
委婉待续19 小时前
java抽奖系统(八)
java·开发语言·状态模式
m0_748241121 天前
前端监控之sourcemap精准定位和还原错误源码
前端·状态模式
m0_748245172 天前
前端下载文件的几种方式使用Blob下载文件
前端·状态模式
m0_748236582 天前
前端如何将pdf等文件传入后端
前端·pdf·状态模式
MatthewMao2 天前
设计模式12:状态模式
设计模式·状态模式
小白64023 天前
浅谈目前我开发的前端项目用到的设计模式
前端·设计模式·状态模式
xyz20115 天前
Flink State面试题和参考答案-(下)
flink·状态模式
方圆想当图灵5 天前
问题解决:发现Excel中的部分内容有问题。是否让我们尽量尝试恢复? 如果您信任此工作簿的源,请单击“是”。
excel·状态模式
攻心的子乐7 天前
satoken 后端获取用户id的原理是啥 用了前端传的那个参数
前端·状态模式