You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中实现上传图片自动压缩的方案求助(不限制上传大小)

NestJS 图片自动压缩Pipe实现方案

针对你当前的图片上传路由,无需限制上传大小,通过自定义Pipe实现自动压缩的可行方案如下:

1. 安装高性能图片处理依赖

使用sharp库处理图片,它在Node.js环境下内存占用低、处理速度快,适合生产环境:

npm install sharp
# 或
yarn add sharp

2. 实现图片压缩Pipe

这个Pipe会拦截上传后的文件对象,对图片进行压缩并更新文件信息:

import { PipeTransform, Injectable, BadRequestException, ArgumentHost } from '@nestjs/common';
import { Express } from 'express';
import * as sharp from 'sharp';

@Injectable()
export class ImageCompressionPipe implements PipeTransform<Express.Multer.File> {
  async transform(file: Express.Multer.File, context: ArgumentHost): Promise<Express.Multer.File> {
    // 二次校验图片类型(确保fileFilter生效)
    if (!file.mimetype.startsWith('image/')) {
      throw new BadRequestException('仅支持图片文件');
    }

    // 从请求参数获取自定义压缩配置(可选)
    const request = context.switchToHttp().getRequest();
    const targetWidth = parseInt(request.query.width) || 1920; // 默认宽1920px,等比缩放
    const quality = parseInt(request.query.quality) || 80; // 默认质量80

    try {
      // 读取原文件并压缩
      const compressedBuffer = await sharp(file.path)
        .resize({ width: targetWidth, withoutEnlargement: true }) // 不放大小于目标尺寸的图片
        .jpeg({ quality })
        .png({ quality })
        .webp({ quality }) // 支持webp格式自动压缩
        .toBuffer();

      // 将压缩后的内容覆盖原文件(也可生成新文件,见下方说明)
      await sharp(compressedBuffer).toFile(file.path);

      // 更新文件对象的大小信息
      file.size = compressedBuffer.length;

      return file;
    } catch (error) {
      throw new BadRequestException('图片压缩失败');
    }
  }
}

可选:生成新压缩文件而非覆盖原文件

如果需要保留原上传文件,可修改Pipe内的写入逻辑:

// 生成带压缩标识的新文件名
const [name, ext] = file.filename.split('.');
const compressedFilename = `${name}-compressed.${ext}`;
const compressedPath = `${file.destination}/${compressedFilename}`;

// 写入新文件
await sharp(compressedBuffer).toFile(compressedPath);

// 更新文件对象信息
file.filename = compressedFilename;
file.path = compressedPath;
file.size = compressedBuffer.length;

3. 在路由中使用压缩Pipe

直接在@UploadedFile()装饰器中加入自定义Pipe即可:

@Post('upload/banner/:postId')
@UseInterceptors(
  FileInterceptor('file', {
    storage: diskStorage({
      destination: './files/posts/banners',
    }),
    fileFilter: imageFileFilter,
  }),
)
async uploadAnonymousPostBanner(
  @UploadedFile(ImageCompressionPipe) file: Express.Multer.File,
  @CurrentUserCookie('userId') userId: string,
  @Param('postId') postId: string,
  @Query('postCode') postCode:string
) {
  console.log(file); // 此时file已完成压缩,size为压缩后大小
  const uploadImgFile = await this.postsService.uploadPostBannerImg(
    userId,
    postId,
    file.filename,
    postCode
  );
  return uploadImgFile;
}

关键说明

  • 压缩参数可根据业务需求调整:比如固定尺寸、动态接收前端参数、强制转换为webp格式以获得更高压缩比。
  • sharp会自动处理不同图片格式,无需额外判断格式类型。
  • 确保文件存储目录具备写入权限,避免压缩后无法写入文件。

内容的提问来源于stack exchange,提问作者INVISIBLE BOY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:50:27