第一章:毕业设计の终极挑战

"同学,你这毕业设计要做文件管理系统?还要支持10G大文件上传?"导师推了推眼镜,我仿佛看到他头顶飘着"这届学生真难带"的弹幕。

"是的老师!还要兼容IE8!"我拍着胸脯保证,内心OS:现在跑路还来得及吗?

于是我这个网络工程专业的菜鸟,开始了用Vue3+原生JS手搓百度WebUploader的奇幻之旅。毕竟谁让咱学校机房还跑着Windows7+IE9呢?(微软:这锅我不背)


第二章:前端の魔改之路

文件选择器(兼容IE8版)
// 魔改后的文件选择器(支持文件夹)
function createFileInput(callback) {
  const input = document.createElement('input');
  input.type = 'file';
  input.webkitdirectory = true; // Chrome
  input.directory = true; // Firefox
  input.multiple = true;
  
  // IE8兼容方案(手动选择文件)
  if (isIE8()) {
    input.onchange = function() {
      const files = [];
      for (let i = 0; i < this.files.length; i++) {
        files.push(this.files[i]);
      }
      callback(files);
    };
  } else {
    // 现代浏览器处理文件夹
    input.onchange = function() {
      const files = [];
      const walkFiles = (entry) => {
        if (entry.isFile) {
          entry.file(file => files.push(file));
        } else if (entry.isDirectory) {
          const reader = entry.createReader();
          reader.readEntries(entries => {
            entries.forEach(walkFiles);
          });
        }
      };
      
      if (this.files) {
        // 非IE的直接获取
        Array.from(this.files).forEach(file => files.push(file));
      } else {
        // WebKit API处理
        const items = this.webkitEntries;
        items.forEach(walkFiles);
      }
      callback(files);
    };
  }
  
  input.click();
}
断点续传核心(LocalStorage版)
// 进度存储管理器(兼容所有浏览器)
class UploadProgressManager {
  constructor() {
    this.storageKey = 'file_upload_progress';
    this.progressData = this.loadProgress();
  }

  loadProgress() {
    try {
      const data = localStorage.getItem(this.storageKey);
      return data ? JSON.parse(data) : {};
    } catch (e) {
      console.error('LocalStorage error:', e);
      return {};
    }
  }

  saveProgress(fileId, chunkIndex, uploadedSize) {
    if (!this.progressData[fileId]) {
      this.progressData[fileId] = {};
    }
    this.progressData[fileId][chunkIndex] = uploadedSize;
    
    try {
      // 分片存储防止超过5MB限制
      const chunkSize = 1000; // 每个存储项最多1000个分片
      const keys = Object.keys(this.progressData[fileId]);
      
      for (let i = 0; i < keys.length; i += chunkSize) {
        const chunk = keys.slice(i, i + chunkSize);
        const chunkData = {};
        chunk.forEach(k => {
          chunkData[k] = this.progressData[fileId][k];
        });
        localStorage.setItem(`${this.storageKey}_${fileId}_${Math.floor(i/chunkSize)}`, 
                             JSON.stringify(chunkData));
      }
    } catch (e) {
      console.error('Progress save failed:', e);
    }
  }

  // 其他方法省略...(实际代码有完整实现)
}

第三章:后端のPython救赎

Flask分片接收接口
from flask import Flask, request, jsonify
import os
from Crypto.Cipher import AES
import base64

app = Flask(__name__)
UPLOAD_FOLDER = '/tmp/uploads'
SECRET_KEY = b'ThisIsASecretKey123'  # 生产环境请使用更安全的密钥

# 文件分片处理
@app.route('/upload', methods=['POST'])
def upload_chunk():
    file_id = request.form['fileId']
    chunk_index = int(request.form['chunkIndex'])
    total_chunks = int(request.form['totalChunks'])
    file_name = request.form['fileName']
    
    # 解密文件内容(前端加密后传输)
    encrypted_data = request.files['file'].read()
    cipher = AES.new(SECRET_KEY, AES.MODE_EAX)
    nonce = encrypted_data[:16]
    ciphertext = encrypted_data[16:-16]
    tag = encrypted_data[-16:]
    decrypted = cipher.decrypt_and_verify(ciphertext, tag)
    
    # 保存分片
    chunk_path = os.path.join(UPLOAD_FOLDER, f"{file_id}.part{chunk_index}")
    with open(chunk_path, 'wb') as f:
        f.write(decrypted)
    
    # 如果是最后一个分片,合并文件
    if chunk_index == total_chunks - 1:
        merge_file(file_id, total_chunks, file_name)
    
    return jsonify({'status': 'success'})

def merge_file(file_id, total_chunks, file_name):
    final_path = os.path.join(UPLOAD_FOLDER, file_name)
    with open(final_path, 'wb') as outfile:
        for i in range(total_chunks):
            chunk_path = os.path.join(UPLOAD_FOLDER, f"{file_id}.part{i}")
            with open(chunk_path, 'rb') as infile:
                outfile.write(infile.read())
            os.remove(chunk_path)
    
    # 这里可以添加阿里云OSS上传代码
    # upload_to_oss(final_path, file_name)

第四章:兼容性の血泪史

  1. IE8的绝望

    • 发现FileReader不支持?改用Flash方案
    • 没有Promise?手动实现简易版
    • XMLHttpRequest没有onload?用onreadystatechange
  2. 文件夹结构保留

    // 构建文件路径树
    function buildFileTree(files) {
      const tree = {};
      files.forEach(file => {
        const pathParts = file.webkitRelativePath ? 
          file.webkitRelativePath.split('/') : 
          [file.name]; // IE fallback
        
        let current = tree;
        pathParts.forEach((part, i) => {
          if (!current[part]) {
            current[part] = i === pathParts.length - 1 ? 
              file : { __isDir: true };
          }
          current = current[part];
        });
      });
      return tree;
    }
    

第五章:最终成果展示

经过3个月的奋战(和无数杯咖啡),我的"超级文件管理系统"终于诞生了!

核心功能

  • ✅ 10G文件秒传(分片上传)
  • ✅ 浏览器关闭后进度不丢失(LocalStorage+IndexedDB双保险)
  • ✅ 文件夹上传保留完整结构
  • ✅ AES-256加密传输+存储
  • ✅ 兼容IE8到Chrome120全系列
  • ✅ 后端Python实现断点续传

演示效果

// 前端调用示例
const uploader = new FileUploader({
  server: '/upload',
  chunkSize: 5 * 1024 * 1024, // 5MB分片
  encrypt: true,
  onProgress: (percent) => {
    console.log(`上传进度: ${percent}%`);
  }
});

// 上传整个文件夹
document.getElementById('uploadBtn').onclick = () => {
  createFileInput((files) => {
    const fileTree = buildFileTree(files);
    uploader.uploadTree(fileTree);
  });
};

第六章:求职の逆袭

现在这个项目已经成为我的求职神器:

  • 面试官:“请描述你遇到的最大技术挑战”
  • 我:“老师,您听说过IE8兼容大文件上传吗?”

求职福利
加入我们的QQ群:374992201,不仅可以:

  1. 免费获取完整源代码
  2. 获得7*24小时技术支持
  3. 参与红包雨活动(最高99元)
  4. 推荐工作机会(师兄师姐都在群里)

PS:群文件里有《IE8兼容性终极指南》和《大文件上传避坑手册》,都是我用头发换来的经验啊!

(最后弱弱地问:有HR大佬在看吗?招前端开发吗?会写IE8兼容代码的那种…)

将组件复制到项目中

示例中已经包含此目录
image

引入组件

image

配置接口地址

接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表
参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de
image

处理事件

image

启动测试

image

启动成功

image

效果

image

数据库

image

效果预览

文件上传

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传
文件续传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。
文件夹上传

批量下载

支持文件批量下载
批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。
下载续传

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。
文件夹下载

下载示例

点击下载完整示例

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐