• 文件分片和断点虚传


    前端代码

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

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

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

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

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

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

    HTML 部分
    DOCTYPE html>
    <html>
    <head>
        <title>File Uploadtitle>
    head>
    <body>
        <input type="file" id="fileInput">
        <button onclick="uploadFile()">Uploadbutton>
        <div id="uploadStatus">div>
        <progress id="uploadProgress" value="0" max="100">progress>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    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)}%)`;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    优化点说明

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

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

    后端代码

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

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

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

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

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

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

    示例代码

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

    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);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    优化点说明

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

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

  • 相关阅读:
    如何处理 Angular 单页面应用里的 a 标签,避免点击后重新加载整个应用
    推荐一个python、AI学习社区:ShowMeAI
    自动化测试
    NX二次开发-设置尺寸的附加尺寸UF_DRF_set_appended_text
    【备考网络工程师】如何备考2023年网络工程师之错题集篇(2)
    危重病入院镁浓度与乳酸酸中毒的关系
    Kotlin读书笔记之优雅且高效的Kotlin
    技术分享|新代币标准的讨论
    勤于奋国外LEAD最近一些常态
    Google Earth Engine(GEE)——全球洪水数据库 v1 (2000-2018年)
  • 原文地址:https://blog.csdn.net/sunyuhua_keyboard/article/details/134417583