您现在的位置是:网站首页 > 文件上传与下载处理文章详情

文件上传与下载处理

文件上传处理

Express框架通过中间件multer处理文件上传。multer是一个Node.js中间件,用于处理multipart/form-data类型的数据,主要用于文件上传。安装multer后,可以轻松配置上传路径、文件过滤和大小限制。

const express = require('express');
const multer = require('multer');
const path = require('path');

const app = express();

// 配置存储
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    cb(null, Date.now() + path.extname(file.originalname));
  }
});

// 文件过滤
const fileFilter = (req, file, cb) => {
  if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
    cb(null, true);
  } else {
    cb(new Error('Unsupported file type'), false);
  }
};

const upload = multer({
  storage: storage,
  limits: { fileSize: 1024 * 1024 * 5 }, // 5MB限制
  fileFilter: fileFilter
});

// 单文件上传路由
app.post('/upload', upload.single('file'), (req, res) => {
  res.send('File uploaded successfully');
});

app.listen(3000);

多文件上传使用upload.array()方法:

app.post('/upload-multiple', upload.array('files', 5), (req, res) => {
  // 限制最多5个文件
  res.send(`${req.files.length} files uploaded successfully`);
});

文件下载处理

Express提供res.download()方法实现文件下载功能。该方法会自动设置适当的Content-TypeContent-Disposition头部。

app.get('/download', (req, res) => {
  const filePath = path.join(__dirname, 'uploads', 'example.pdf');
  res.download(filePath, 'custom-filename.pdf', (err) => {
    if (err) {
      res.status(500).send('File download failed');
    }
  });
});

对于大文件下载,建议使用流式处理以避免内存问题:

const fs = require('fs');

app.get('/download-large', (req, res) => {
  const filePath = path.join(__dirname, 'uploads', 'large-video.mp4');
  const stat = fs.statSync(filePath);
  
  res.writeHead(200, {
    'Content-Type': 'video/mp4',
    'Content-Length': stat.size,
    'Content-Disposition': 'attachment; filename=video.mp4'
  });

  const readStream = fs.createReadStream(filePath);
  readStream.pipe(res);
});

文件管理最佳实践

  1. 安全处理
    • 永远不要信任上传的文件名
    • 限制文件类型和大小
    • 将上传目录设置为不可执行
// 安全文件名处理
function sanitizeFilename(filename) {
  return filename.replace(/[^a-z0-9\.-]/gi, '_').toLowerCase();
}
  1. 存储优化

    • 考虑使用云存储服务(AWS S3、阿里云OSS等)
    • 实现分块上传大文件
    • 定期清理临时文件
  2. 性能考虑

    • 使用CDN分发静态文件
    • 实现断点续传功能
    • 考虑文件压缩选项

高级文件处理

实现图片即时处理(如缩略图生成):

const sharp = require('sharp');

app.post('/upload-image', upload.single('image'), async (req, res) => {
  try {
    await sharp(req.file.path)
      .resize(300, 300)
      .toFile(`uploads/thumbnails/${req.file.filename}`);
    
    res.send('Image processed successfully');
  } catch (err) {
    res.status(500).send('Image processing failed');
  }
});

实现文件分块上传:

// 前端分块上传示例代码
async function uploadFileInChunks(file) {
  const chunkSize = 1024 * 1024; // 1MB
  const totalChunks = Math.ceil(file.size / chunkSize);
  
  for (let i = 0; i < totalChunks; i++) {
    const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('chunkIndex', i);
    formData.append('totalChunks', totalChunks);
    formData.append('fileId', file.name + file.size);
    
    await fetch('/upload-chunk', {
      method: 'POST',
      body: formData
    });
  }
  
  // 通知服务器合并分块
  await fetch('/merge-chunks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      fileId: file.name + file.size,
      fileName: file.name,
      totalChunks: totalChunks
    })
  });
}

错误处理与日志记录

完善的错误处理机制对文件操作至关重要:

// 全局错误处理中间件
app.use((err, req, res, next) => {
  if (err.code === 'LIMIT_FILE_SIZE') {
    return res.status(413).send('File too large');
  }
  if (err.message === 'Unsupported file type') {
    return res.status(415).send('Invalid file type');
  }
  
  console.error('File upload error:', err);
  res.status(500).send('File processing error');
});

// 文件操作日志记录
function logFileOperation(action, filePath, userId) {
  const timestamp = new Date().toISOString();
  const logEntry = `${timestamp} [${action}] ${filePath} by user ${userId}\n`;
  
  fs.appendFile('file_operations.log', logEntry, (err) => {
    if (err) console.error('Failed to log file operation', err);
  });
}

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步