图片分片上传功能的实践

在 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 开发中常用的技术之一。

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

相关推荐
GDAL22 分钟前
HTML 中的 Canvas 样式设置全解
javascript
m0_5287238128 分钟前
HTML中,title和h1标签的区别是什么?
前端·html
Dark_programmer29 分钟前
html - - - - - modal弹窗出现时,页面怎么能限制滚动
前端·html
GDAL34 分钟前
HTML Canvas clip 深入全面讲解
前端·javascript·canvas
禾苗种树35 分钟前
在 Vue 3 中使用 ECharts 制作多 Y 轴折线图时,若希望 **Y 轴颜色自动匹配折线颜色**且无需手动干预,可以通过以下步骤实现:
前端·vue.js·echarts
GISer_Jing40 分钟前
Javascript排序算法(冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序)详解
javascript·算法·排序算法
贵州数擎科技有限公司1 小时前
使用 Three.js 实现流光特效
前端·webgl
JustHappy1 小时前
「我们一起做组件库🌻」做个面包屑🥖,Vue的依赖注入实战💉(VersakitUI开发实录)
前端·javascript·github
拉不动的猪1 小时前
刷刷题16
前端·javascript·面试
kiramario1 小时前
【结束】JS如何不通过input的onInputFileChange使用本地mp4文件并播放,nextjs下放入public文件的视频用video标签无法打开
开发语言·javascript·音视频