图片分片上传功能的实践

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

HTML部分

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

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

JavaScript部分

然后,我们使用 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框架实现了文件上传的接口:

javascript 复制代码
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 开发中常用的技术之一。

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

相关推荐
雪芽蓝域zzs几秒前
第三十五节:Axios 统一错误拦截、401 Token 过期处理
前端·javascript·vue.js
XIE3926 分钟前
TipKit:开源富文本编辑器套件,一套逻辑,任意风格!
前端·笔记·开源
范什么特西20 分钟前
一些常用名词
开发语言·前端·javascript
晴天1621 分钟前
前端打包工具全景解析
前端
晴天1623 分钟前
Vite vs Webpack 全方位对比
前端·webpack·node.js
体毛旺盛的猿25 分钟前
HarmonyOS开发面试题
前端·华为·harmonyos
anOnion40 分钟前
构建无障碍组件之Landmarks Pattern
前端·html·交互设计
牧瀬クリスだ41 分钟前
前端三件套基础之JS!!!!
前端·javascript
乌夷44 分钟前
JavaScript 的事件循环
开发语言·javascript·ecmascript
风骏时光牛马44 分钟前
提示词工程:大模型交互的核心塑造技术
前端