图片分片上传功能的实践

在 Web 开发中,图片上传是一个常见的需求,特别是对于大文件,为了提高上传效率和稳定性,常常需要将文件进行分片上传。本文将介绍如何利用 JavaScript 和 Axios 库实现图片分片上传功能。

HTML部分

首先,我们在 HTML 中创建一个文件上传的 input 元素,以及显示上传进度的 progress 元素和开始上传按钮。

<body>
    // 上传组件
    <input type="file" id="upload"/> 
    // 进度条
    <progress id="progress" value="0" max="100"></progress> 
    // 上传按钮
    <button id="start">开始上传</button>
</body>

JavaScript部分

然后,我们使用 JavaScript 编写上传功能。以下是 JavaScript 代码:

import axios from "axios";
// 上传组件
const upload = document.querySelector('#upload');
// 进度条
const progress = document.querySelector('#progress');
// 上传按钮
const start = document.querySelector('#start');

// 上传的服务器地址
const uploadApiPath = `http://localhost:8888/upload`;

// 点击开始上传按钮触发事件
start.addEventListener('click', () => {
  // 获取文件
  const [file] = upload.files;

  if (!file) {
    throw new Error('请选择文件');
  }
  
  // 分片大小,2MB
  const chunkSize = 1024 * 1024 * 2; 

  // 创建文件切片
  const createFileChunk = (file, size = chunkSize) => {
    const fileChunkList = [];
    let cur = 0;
    while (cur < file.size) {
      const chunk = file.slice(cur, cur + size);
      fileChunkList.push(chunk);
      cur += size;
    }

    return fileChunkList;
  };

  const chunks = createFileChunk(file);

  // 上传文件切片
  const uploadChunks = async (chunks) => {
    const requestList = chunks.map((chunk, index) => {
      const formData = new FormData();
      formData.append('file', chunk);
      formData.append('filename', file.name);
      formData.append('index', index);
      return { formData };
    });
    
    // 分片上传列表
    const requestListLength = requestList.length;
    // 已上传完成数
    let completed = 0;

    // 递归上传文件切片
    const upload = async () => {
      if (completed >= requestListLength) {
        // 上传完成
        console.log('上传完成');
        return;
      }
      const request = requestList[completed];
      
      try {
        // 发送 POST 请求上传文件切片
        const res = await axios.post(uploadApiPath, request.formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        });
        // 更新上传进度
        progress.value = Math.floor((completed + 1) / requestListLength * 100);
        completed++;
        await upload();
      } catch (error) {
        console.log(error);
      }
    };

    await upload();
  };

  uploadChunks(chunks).then(r => {});

});

服务端部分

以下是服务端部分的代码,基于Express框架实现了文件上传的接口:

import express from 'express';
import bodyParser from 'body-parser';
import fileUpload from 'express-fileupload';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { existsSync, unlinkSync, writeFileSync, appendFileSync } from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const app = express();

// 开启跨域
app.all('*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
})

// 处理urlencoded请求
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// 使用express-fileupload中间件处理文件上传
app.use(fileUpload({}));

// 处理静态文件
app.use('/', express.static('static'));

const port = 8888;

app.get('/', (req, res) => {
    res.send({
      code: 200,
      message: 'Hello World!'
    });
})

app.post('/upload', (req, res) => {
  const { file } = req.files;
  const { filename, index } = req.body;

  console.log(file, filename, index)

  const filePath = resolve(__dirname, `./static/${filename}`);

  const url = `http://localhost:${port}/${filename}`

  if (parseInt(index) === 0) {
    if (existsSync(filePath)) {
      // 文件已存在,删除
      unlinkSync(filePath);
    }
    // 写入一个新文件
    writeFileSync(filePath, file.data);

    res.send({
      code: 200,
      message: '创建文件成功',
      url
    });
  } else {
    // 追加文件
    appendFileSync(filePath, file.data);
    res.send({
      code: 200,
      message: '追加文件成功',
      url
    });
  }
})

app.listen(port, () => {
  console.log(`Server is running on port http://localhost:${port}`);
})

通过本文的介绍,我们学习了如何使用 JavaScript 和 Axios 库实现图片分片上传功能,同时也了解了服务端部分的实现细节。这种方式可以提高大文件上传的效率和稳定性,是 Web 开发中常用的技术之一。

希望本文对您有所帮助,谢谢阅读!

原文链接:https://juejin.cn/post/7343060153807863823 作者:鼠突猛进

(0)
上一篇 2024年3月6日 下午4:57
下一篇 2024年3月6日 下午5:08

相关推荐

发表回复

登录后才能评论