教程 express tutorial

文件上传与图片处理

在本章节中,我们将介绍如何在 Express 应用中实现文件上传和图片处理功能。我们将使用 Multer 中间件来处理上传的文件,并使用 Sharp 库对图片进行基本的处理操作,如缩放、裁剪和格式转换。通过这个例子,您将学会如何处理用户上传的文件,并对图片进行简单的操作。

1. 安装依赖

首先,您需要安装 Multer 和 Sharp 库:

bash
npm install multer sharp

`

  • Multer:用于处理 multipart/form-data 类型的表单数据,特别是文件上传。
  • Sharp:用于处理和转换图片,如缩放、裁剪、格式转换等。

2. 设置 Multer 中间件

Multer 中间件用于处理文件上传。我们将配置 Multer 来存储文件,并设置上传文件的大小限制。

2.1 配置文件存储

首先,我们需要创建一个存储配置,指定上传的文件存储位置和文件名。

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

// 设置存储引擎
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');  // 文件存储的目录
  },
  filename: (req, file, cb) => {
    cb(null, Date.now() + path.extname(file.originalname));  // 文件名使用时间戳,避免重复
  }
});

// 创建 Multer 实例
const upload = multer({
  storage: storage,
  limits: { fileSize: 10 * 1024 * 1024 },  // 限制文件大小为 10MB
});

module.exports = upload;

2.2 创建上传路由

接下来,我们在 Express 中创建一个路由,用于接收文件上传。

js
const express = require('express');
const upload = require('../middlewares/upload');
const path = require('path');

const router = express.Router();

// 上传单个文件
router.post('/upload', upload.single('image'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: 'No file uploaded' });
  }
  res.status(200).json({
    message: 'File uploaded successfully',
    file: req.file,
    filePath: `/uploads/${req.file.filename}`,  // 返回文件的相对路径
  });
});

module.exports = router;

这里,我们使用了 upload.single('image') 来处理上传单个文件的请求。'image' 是表单中上传文件的字段名。

3. 图片处理

我们将使用 Sharp 来处理上传的图片,支持操作如缩放、裁剪和格式转换。

3.1 图片缩放

假设我们需要上传的图片在服务器中保存为原始尺寸,但我们也希望生成一张缩小版的图片,用于预览。

js
const sharp = require('sharp');
const path = require('path');
const fs = require('fs');

// 处理图片,生成缩小版图片
router.post('/upload', upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: 'No file uploaded' });
  }

  const { filename, path: filePath } = req.file;

  // 生成缩小版图片
  const thumbnailPath = path.join('uploads', 'thumbnails', `thumb_${filename}`);
  
  try {
    await sharp(filePath)
      .resize(150, 150)  // 设置宽高为 150x150
      .toFile(thumbnailPath);

    res.status(200).json({
      message: 'File uploaded and thumbnail generated',
      file: req.file,
      filePath: `/uploads/${filename}`,
      thumbnailPath: `/uploads/thumbnails/thumb_${filename}`,
    });
  } catch (err) {
    res.status(500).json({ message: 'Error processing image', error: err });
  }
});

3.2 图片裁剪

如果我们需要用户上传的图片裁剪为指定尺寸,可以使用 Sharp 来裁剪图片。

js
router.post('/upload', upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: 'No file uploaded' });
  }

  const { filename, path: filePath } = req.file;

  // 设置裁剪区域
  const cropWidth = 200;
  const cropHeight = 200;

  const croppedImagePath = path.join('uploads', 'cropped', `crop_${filename}`);

  try {
    await sharp(filePath)
      .extract({ width: cropWidth, height: cropHeight, left: 0, top: 0 })  // 从图片左上角开始裁剪
      .toFile(croppedImagePath);

    res.status(200).json({
      message: 'File uploaded and image cropped',
      file: req.file,
      filePath: `/uploads/${filename}`,
      croppedImagePath: `/uploads/cropped/crop_${filename}`,
    });
  } catch (err) {
    res.status(500).json({ message: 'Error cropping image', error: err });
  }
});

3.3 图片格式转换

除了缩放和裁剪,Sharp 还支持将图片转换为其他格式,如将上传的 JPG 图片转换为 PNG 格式。

js
router.post('/upload', upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: 'No file uploaded' });
  }

  const { filename, path: filePath } = req.file;

  const convertedImagePath = path.join('uploads', 'converted', `${path.parse(filename).name}.png`);

  try {
    await sharp(filePath)
      .toFormat('png')  // 转换为 PNG 格式
      .toFile(convertedImagePath);

    res.status(200).json({
      message: 'File uploaded and image converted',
      file: req.file,
      filePath: `/uploads/${filename}`,
      convertedImagePath: `/uploads/converted/${path.parse(filename).name}.png`,
    });
  } catch (err) {
    res.status(500).json({ message: 'Error converting image', error: err });
  }
});

4. 图片压缩

如果文件上传后过大,我们也可以使用 Sharp 来压缩图片。

js
router.post('/upload', upload.single('image'), async (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: 'No file uploaded' });
  }

  const { filename, path: filePath } = req.file;

  const compressedImagePath = path.join('uploads', 'compressed', `compressed_${filename}`);

  try {
    await sharp(filePath)
      .jpeg({ quality: 70 })  // 压缩成质量为 70 的 JPEG 格式
      .toFile(compressedImagePath);

    res.status(200).json({
      message: 'File uploaded and image compressed',
      file: req.file,
      filePath: `/uploads/${filename}`,
      compressedImagePath: `/uploads/compressed/compressed_${filename}`,
    });
  } catch (err) {
    res.status(500).json({ message: 'Error compressing image', error: err });
  }
});

5. 总结

在本章节中,您学会了如何使用 Multer 来处理 Express 中的文件上传,并结合 Sharp 实现了基本的图片处理功能,包括缩放、裁剪、格式转换和压缩。您可以根据实际需求,扩展更多功能,例如设置上传文件的类型限制、对多个文件的处理等。

通过这些操作,您可以为 Express 应用添加强大的文件上传和处理功能,支持用户上传图片并对其进行各种操作。