SoFunction
Updated on 2025-04-05

Using Vue3+ElementPlus front-end to implement the entire process of shard upload

1. What is shard upload

Cut a file into a series of data fragments of specific sizes and upload these data fragments to the server separately;

After all uploads are completed, the server will merge these data fragments into a complete resource;

During the upload process, the upload is interrupted due to external factors (such as network fluctuations), and the upload progress of the file will be retained the next time it is uploaded (renewal point transmission);

2. Upload component templates

Contains three parts:

  • Upload components, use el-upload
  • Progress bar component, using el-progress
  • Upload the complete status component, customize it using el-input
 <el-form-item label="Upload attachment" prop="uploadFile">
   <el-upload
       v-if="!"
       class="upload-demo"
       drag
       :show-file-list="false"
       :action="APP_MANAGEMENT.uploadFile"
        // Pass parameters according to the project's interface       :data="{
         applicationId: applicationId,
         applicationVersion: applicationVersion,
         bucketName: 'app'
       }"
       // Override the default http request       :http-request="handleFileUpload"
   >
     <el-icon class="el-icon--upload">
       <upload-filled />
     </el-icon>
 
     <div v-if="!progress" class="el-upload__text">
       Drop file here or <em>click to upload</em>
     </div>
 
     // Progress bar     <el-progress
        v-else
        :text-inside="true"
        :stroke-width="24"
        :percentage="progress"
        status="success"
       />
   </el-upload>
 
   // Hide the upload file component after successful upload   <div v-else style="display: flex;">
     <el-input v-model="" readonly>
     </el-input>
     <div style="display: flex;">
       <el-button 
           type="primary" 
           :icon="Download" 
           size="small" 
           @click="handleFileDownload" 
          />
       <el-button type="primary" :icon="Delete" size="small" @click="handleFileDel" />
     </div>
   </div>
 </el-form-item>

3. Upload component logic

3.1 Basic ideas

Use el-upload to select a file

Select the successful callback function. You can read file information and use it to verify the legality of the file in the front-end.

After the front-end verification file is legal, slice the file

passRequest pollingPass the slice to the backend

3.2 Select Upload File

In this step, file information can be obtained

Verify the legality of the file based on the file information

After the verification is successful, call the file slice method

/**
  * @description: Select upload file
  * @param file el-upload parameter returned
  */
const handleFileUpload = async (file: any) => {
  ('el-upload Returned parameters === ', );
 
  // If the file is legal, then upload it in pieces  if (await checkMirrorFile(file)) {
    // File information    const files = ;
    // Slices starting from 0    const shardIndex = 0;
    // Call file slicing method    uploadFileSilce(files, shardIndex);
  // If the file is illegal, then prompt  } else {
    ('Please check whether the file is legal!  ');
  }
};

3.3 Verify whether the file is legal

Verify file format

Verify file size

Call the interface to verify the remaining space of the disk

/**
  * @description: Verify file legality
  */
const checkMirrorFile = async (file) => {
    // Verify file format, support .zip/.tar    const fileType = ('.')
    if (fileType[ - 1] !== 'zip' && fileType[ - 1] !== 'tar') {
        ('File format is wrong, only .zip/.tar')
        return false
    }
 
    // Verify file size    const fileSize = ;
    // Is the file size exceeding 2G    if (fileSize > 2 * 1024 * 1024 * 1024) {
        ('Upload file size cannot exceed 2G')
        return false
    }
 
    // Call the interface to verify the file legality, such as determining whether the disk space is sufficient    const res = await checkMirrorFileApi()
    if ( !== 200) {
        ('Cannot view the available space of the disk for the time being, please try again')
        return false
    }
    // Check the disk capacity    if ( &&  > 0) {
        let saveSize = 0
        (i => {
            // Disk space assignment            if ( === '/dev/mapper/centos-root') {
                // The return value is GB, converted to byte B                saveSize =  * 1024 * 1024 * 1024
            }
        })
        // The uploaded file size does not exceed the available space of the disk        if (fileSize < saveSize) {
            return true
        } else {
            ('File size exceeds the available space capacity of disk')
            return false
        }
    } else {
        ('File size exceeds the available space capacity of disk')
        return false
    }
}

3.4 File encryption

File upload here is encrypted with MD5, and it requires installation dependencies spark-md5

npm i spark-md5

/**
  * @description: File encryption processing
  */
const getMD5 = (file: any): Promise<string> => new Promise((resolve, reject) => {
  const spark = new ();
  // Get file binary data  const fileReader = new FileReader();
  (file); // file is the obtained file  // Execute functions asynchronously  ('load', (e: any) => {
    ();
    const md5: string = ();
    resolve(md5);
  });
  ('error', (e) => {
    reject(e);
  });
});

3.5 Merge files

The parameters required by the interface are:

  • file name
  • File unique hash value

After the interface merge is completed, the front-end displays the uploaded file name

/**
  * @description: Merge files
  * @param name File name
  * @param hash file unique hash value
  * @return Name
  */
const composeFile = async (name: string, hash: string) => {
  ('Start file merging');
  const res = await uploadFileMerge({
    applicationId: ,
    applicationVersion: ,
    bucketName: 'app',
    fileName: name,
    hash,
  });
  ('Backend interface merge files ===', res);
  if ( === 200 && ) {
    // After the merge is successful, adjust the uploaded file name     = name;
  }
};

3.6 File slice upload

Interface polling - carry one file slice to the backend at a time; after the backend receives the slice and returns the successful status code, the next slice upload is performed

/**
  * @description: Sharding function
  * @param file
  * @param shardIndex Number of shards
  */
const uploadFileSilce = async (file: File, shardIndex: number) => {
      // file name      const { name } = file;
      // File size      const { size } = file;
      // Size      const shardSize = 1024 * 1024 * 5;
      // File encryption      const hash: string = await getMD5(file);
      // Total number of shards      const shardTotal = (size / shardSize);
 
      // If the current shard index is greater than the total shard count      if (shardIndex >= shardTotal) {
         = false;
         = 100;
        // Merge files        composeFile(name, hash);
        return;
      }
 
      // Where the file starts and ends      const start = shardIndex * shardSize;
      const end = (start + shardSize, size);
      // Start cutting      const packet = (start, end);
      
      // Splicing request parameters      const formData = new FormData();
      ('file', packet);
      ('applicationId', );
      ('applicationVersion', );
      ('bucketName', 'app');
      ('hash', hash);
      ('shardSize', shardSize as unknown as string);
      ('seq', shardIndex as unknown as string);
 
      // If the current shard index is less than the total shard count      if (shardIndex < shardTotal) {
        // The progress bar retains two decimal places to display         = Number(((shardIndex / shardTotal) * 100).toFixed(2)) * 1;
        // Call the file upload interface        const res = await uploadFile(formData);
        if ( !== 200) {
          ('Upload failed');
           = 0;
          return;
        }
        if ( === 200 &&  === 200) {
          // Here are the operations performed after all slices are uploaded successfully          ('Uploaded successfully');
        }
        // eslint-disable-next-line no-param-reassign
        shardIndex++;
        // Recursively call sharding function        uploadFileSilce(file, shardIndex);
      }
    };

4. Reference article

4.1 Article link

Upload and download of front-end large files (slice upload)

4.2 Notes mentioned in reference to the article

4.2.1 nginx upload size limit

The default upload size of nginx is 1MB. If it exceeds 1MB, you need to modify the nginx configuration to lift the upload limit.

4.2.2 Large file download

/**
  * @description: Dynamically create a tag to realize large file download
  */
const downloadMirror = async (item) => {
  let t = {
    id: ,
  }
  const res = await downloadMirrorApi(t)
  if (["content-disposition"]) {
    let temp = ["content-disposition"].split(";")[1].split("filename=")[1]
    let fileName = decodeURIComponent(temp)
    //Realize file download by creating a tag    let link = ('a')
     = fileName
     = 'none'
     = 
    (link)
    ()
    (link)
  } else {
    ElMessage({
      message: 'This file does not exist',
      type: 'warning',
    })
  }
}

Summarize

This is the article about using Vue3+ElementPlus front-end to realize shard upload. For more related content on Vue3+ElementPlus front-end shard upload, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!