返回

大文件上传优雅解决传输失败问题,保证用户传输体验

前端

前言

在大文件传输过程中,如果因刷新页面或临时失败导致传输中断,用户需要从头重新传输,非常影响用户体验。因此,需要一种方法来记录传输进度,以便下次直接从失败处继续传输。

解决方法

使用localStorage来记录传输进度。localStorage是浏览器提供的存储API,可以存储字符串键值对。具体步骤如下:

  1. 计算文件MD5、哈希值或其他唯一标识。
  2. 将计算出的唯一标识存储在localStorage中,键为文件的唯一标识,值为文件的传输进度。
  3. 当文件传输失败时,从localStorage中读取文件的唯一标识,并从上次传输进度处继续传输。

代码示例

// React组件
import React, { useState } from 'react';

const FileUpload = () => {
  const [file, setFile] = useState(null);
  const [progress, setProgress] = useState(0);

  const handleChange = (e) => {
    setFile(e.target.files[0]);
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    // 计算文件MD5
    const md5 = calculateMD5(file);

    // 将MD5和传输进度存储在localStorage中
    localStorage.setItem(md5, progress);

    // 开始上传文件
    uploadFile(file, md5, progress);
  };

  const uploadFile = (file, md5, progress) => {
    // 创建XMLHttpRequest对象
    const xhr = new XMLHttpRequest();

    // 设置上传事件监听器
    xhr.upload.addEventListener('progress', (e) => {
      // 计算传输进度
      const newProgress = Math.round((e.loaded / e.total) * 100);

      // 更新localStorage中的传输进度
      localStorage.setItem(md5, newProgress);

      // 更新组件状态
      setProgress(newProgress);
    });

    // 设置请求头
    xhr.setRequestHeader('Content-Type', 'multipart/form-data');

    // 打开请求
    xhr.open('POST', 'http://example.com/upload');

    // 发送请求
    xhr.send(file);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="file" onChange={handleChange} />
      <button type="submit">上传</button>
      <progress value={progress} max="100" />
    </form>
  );
};

export default FileUpload;

// Koa路由
const router = require('koa-router')();

router.post('/upload', async (ctx) => {
  // 获取文件
  const file = ctx.request.files.file;

  // 计算文件MD5
  const md5 = calculateMD5(file);

  // 从localStorage中读取传输进度
  const progress = localStorage.getItem(md5);

  // 如果传输进度不为0,则从上次传输进度处继续传输
  if (progress) {
    ctx.request.req.headers['Content-Range'] = `bytes ${progress}-`;
  }

  // 将文件保存到服务器
  const filePath = `./uploads/${file.name}`;
  const fileStream = fs.createWriteStream(filePath);
  fileStream.write(file.data);
  fileStream.end();

  // 返回成功信息
  ctx.body = {
    success: true,
    message: '文件上传成功',
  };
});

总结

通过使用localStorage记录传输进度,可以优雅地解决大文件上传传输失败问题,保证用户传输体验的顺畅性。