使用 Express.js 实现文件上传进度条的方法

在前端开发中,文件上传是一个常见的需求。然而,在上传较大的文件时,用户需要等待较长时间才能完成上传,这会给用户带来不好的体验。为了改善用户体验,我们可以使用进度条来展示上传进度。在本文中,我们将介绍如何使用 Express.js 实现文件上传进度条的方法。

实现思路

使用 Express.js 实现文件上传进度条的方法,主要分为以下几个步骤:

  1. 创建一个上传路由,用于处理文件上传请求。
  2. 使用 multer 中间件,处理文件上传,并将上传进度传递给回调函数。
  3. 在回调函数中,通过 socket.io 将上传进度传递给前端页面。
  4. 在前端页面中,使用进度条组件展示上传进度。

代码实现

后端代码

首先,我们需要创建一个上传路由,用于处理文件上传请求。在路由中,我们使用 multer 中间件,处理文件上传,并将上传进度传递给回调函数。

const express = require('express');
const multer = require('multer');
const path = require('path');
const router = express.Router();

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
  }
});

const upload = multer({
  storage: storage,
  limits: { fileSize: 1000000 },
  fileFilter: function (req, file, cb) {
    checkFileType(file, cb);
  }
}).single('file');

router.post('/upload', function (req, res) {
  upload(req, res, function (err) {
    if (err) {
      console.log(err);
      return res.status(500).send(err.message);
    }
    res.status(200).send('File uploaded successfully');
  });
});

function checkFileType(file, cb) {
  const filetypes = /jpeg|jpg|png/;
  const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
  const mimetype = filetypes.test(file.mimetype);
  if (extname && mimetype) {
    return cb(null, true);
  } else {
    cb('Error: Images Only!');
  }
}

在回调函数中,我们通过 socket.io 将上传进度传递给前端页面。具体实现如下:

const io = require('socket.io')(server);

io.on('connection', function (socket) {
  console.log('Socket connected: ' + socket.id);

  socket.on('start', function (data) {
    console.log('Start uploading: ' + data.filename);
    const stream = ss.createStream();
    const filename = path.basename(data.filename);
    const size = data.size;
    const type = data.type;
    const folder = data.folder;
    const uploadPath = path.join(__dirname, '..', folder, filename);

    ss(socket).emit('stream', stream, { size: size, type: type, filename: filename });

    fs.mkdirSync(path.join(__dirname, '..', folder), { recursive: true });

    const writable = fs.createWriteStream(uploadPath);
    data.stream.pipe(writable);

    data.stream.on('data', function (chunk) {
      const progress = (chunk.length / size) * 100;
      socket.emit('progress', { progress: progress });
    });

    data.stream.on('end', function () {
      console.log('Upload completed: ' + filename);
      socket.emit('end', { filename: filename });
    });
  });
});

前端代码

在前端页面中,我们使用 socket.io 客户端,连接到服务器,并监听上传进度事件。具体实现如下:

const socket = io();

$('#upload-form').submit(function (e) {
  e.preventDefault();
  const file = $('#file-input')[0].files[0];
  const formData = new FormData();
  formData.append('file', file);

  socket.emit('start', {
    filename: file.name,
    size: file.size,
    type: file.type,
    folder: 'uploads'
  });

  const stream = ss.createStream();
  ss(socket).emit('stream', stream, { size: file.size, type: file.type, filename: file.name });

  const blobStream = ss.createBlobReadStream(file);
  const size = 0;
  const progressBar = $('#progress-bar');

  blobStream.on('data', function (chunk) {
    size += chunk.length;
    const progress = Math.floor(size / file.size * 100);
    progressBar.css('width', progress + '%');
    progressBar.text(progress + '%');
    socket.emit('progress', { progress: progress });
  });

  blobStream.pipe(stream);

  socket.on('end', function (data) {
    console.log('Upload completed: ' + data.filename);
    progressBar.css('width', '0%');
    progressBar.text('0%');
  });
});

总结

使用 Express.js 实现文件上传进度条的方法,可以改善用户体验,提高用户满意度。在本文中,我们介绍了实现思路,并给出了具体代码实现。希望本文能够对您有所帮助。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658cef8aeb4cecbf2d2ce909


纠错
反馈