滴水恩情 发表于 2024-11-7 10:45:21

大文件上传

<!-- 上传组件 -->
<template>
<div>
    <input type="file" @change="handleFileChange" />
    <button @click="uploadFile">上传</button>
    <div v-if="progress > 0 && progress < 100">
      <progress :value="progress" max="100"></progress>
      <span>{{ progress }}%</span>
    </div>
</div>
</template>

<script>
export default {
data() {
    return {
      file: null,
      chunkSize: 1024 * ¼00, // 2MB
      totalChunks: 0,
      uploadedChunks: 0,
      progress: 0,
      uploadId: null,
    };
},
methods: {
    handleFileChange(event) {
      this.file = event.target.files;
      this.validateFile();
    },
    validateFile() {
      const allowedTypes = ['image/jpeg', 'image/png', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
      if (!allowedTypes.includes(this.file.type)) {
      alert('文件类型不支持');
      return;
      }
      if (this.file.size > 1024 * 1024 * 10) { // 10MB
      alert('文件大小超过限制');
      return;
      }
      this.totalChunks = Math.ceil(this.file.size / this.chunkSize);
    },
    uploadFile() {
      if (!this.file) {
      alert('请选择文件');
      return;
      }

      // 获取上传 ID
      this.getUploadId().then((uploadId) => {
      this.uploadId = uploadId;
      this.uploadChunks();
      });
    },
    getUploadId() {
      return fetch('/api/upload/init', {
      method: 'POST',
      headers: {
          'Content-Type': 'application/json',
      },
      body: JSON.stringify({
          fileName: this.file.name,
          fileSize: this.file.size,
          fileType: this.file.type,
      }),
      }).then((response) => response.json()).then((data) => data.uploadId);
    },
    uploadChunks() {
      const chunks = this.createChunks();
      const promises = [];

      for (let i = 0; i < this.totalChunks; i++) {
      const chunk = chunks;
      const chunkIndex = i;
      const promise = this.uploadChunk(chunk, chunkIndex).catch((error) => {
          console.error(`上传分片 ${chunkIndex} 失败:`, error);
          return this.uploadChunk(chunk, chunkIndex); // 重试
      });
      promises.push(promise);
      }

      Promise.all(promises).then(() => {
      this.completeUpload();
      });
    },
    createChunks() {
      const chunks = [];
      const fileReader = new FileReader();
      const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;

      let start = 0;
      while (start < this.file.size) {
      const end = Math.min(start + this.chunkSize, this.file.size);
      const chunk = blobSlice.call(this.file, start, end);
      chunks.push(chunk);
      start = end;
      }

      return chunks;
    },
    uploadChunk(chunk, index) {
      return new Promise((resolve, reject) => {
      const formData = new FormData();
      formData.append('uploadId', this.uploadId);
      formData.append('chunkIndex', index);
      formData.append('chunk', chunk);

      fetch('/api/upload/chunk', {
          method: 'POST',
          body: formData,
      }).then((response) => {
          if (response.ok) {
            this.updateProgress(index);
            resolve();
          } else {
            reject(response.statusText);
          }
      }).catch(reject);
      });
    },
    updateProgress(index) {
      this.uploadedChunks++;
      this.progress = (this.uploadedChunks / this.totalChunks) * 100;
    },
    completeUpload() {
      fetch('/api/upload/complete', {
      method: 'POST',
      headers: {
          'Content-Type': 'application/json',
      },
      body: JSON.stringify({
          uploadId: this.uploadId,
      }),
      }).then((response) => response.json()).then((data) => {
      if (data.success) {
          alert('文件上传成功');
      } else {
          alert('文件上传失败');
      }
      });
    },
},
};
</script> 1. 文件选择与预处置惩罚

起首,我们需要创建一个文件选择界面,并对文件进行预处置惩罚,包括文件类型判断和文件巨细判断。
2. 文件切片与并行上传



[*]文件切片:使用 File.prototype.slice 方法将文件切分为多个分片。
[*]并行上传:使用 Promise.all 并行上传所有分片。
3. 秒传与断点续传



[*]秒传:在上传之前,先查抄服务器上是否有雷同的文件。如果有,则直接返回上传成功的相应。
[*]断点续传:在上传过程中记录已上传的分片信息,如果上传中断,可以从上次中断的地方继续上传。
4. 错误重试与控制并发



[*]错误重试:在上传失败时,主动重试上传。
[*]控制并发:通过限制同时上传的分片数量来控制并发,防止服务器过载。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 大文件上传