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

通过Nest API从S3下载文件速度极慢,求优化方案

优化Nest API从S3下载文件速度的方案

1. 复用S3Client实例

你当前每次调用download方法都会新建S3Client,这会带来重复的TCP连接建立、身份验证等额外开销,严重拖慢下载效率。应该将S3Client配置为单例,在模块中全局注入复用:

模块配置示例:

@Module({
  providers: [
    {
      provide: S3Client,
      useFactory: () => {
        return new S3Client({
          credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY_ID,
            secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
          },
          region: process.env.AWS_REGION,
        });
      },
    },
    StorageService,
  ],
  exports: [S3Client, StorageService],
})
export class StorageModule {}

修改后的服务层代码:

async download(key: string): Promise<Readable> {
  const command = new GetObjectCommand({
    Bucket: this.bucket,
    Key: key,
  });
  try {
    const response = await this.s3Client.send(command);
    return response.Body as Readable;
  } catch (err) {
    throw new HttpException('文件下载失败', HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

2. 改用S3预签名URL(最优方案)

让客户端直接从S3下载文件,彻底绕过你的Nest服务器中转,消除带宽和性能瓶颈。服务层仅需生成临时有效的预签名URL返回给前端即可:

服务层新增预签名方法:

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

async getPresignedDownloadUrl(key: string): Promise<string> {
  const command = new GetObjectCommand({
    Bucket: this.bucket,
    Key: key,
  });
  // 生成15分钟内有效的预签名URL,可根据需求调整过期时间
  return getSignedUrl(this.s3Client, command, { expiresIn: 900 });
}

控制器修改:

@Get('v1/api/download/:filename*')
async getDownloadUrl(@Param('filename') filename: string) {
  const url = await this._storageService.getPresignedDownloadUrl(filename);
  return { downloadUrl: url };
}

前端拿到URL后直接发起GET请求即可下载,速度完全由S3和客户端网络决定。

3. 优化流传输配置(必须代理时使用)

如果业务场景要求必须通过Nest中转,可做以下优化:

  • 调整响应Chunk大小:返回StreamableFile时明确指定分块传输头,帮助浏览器更高效处理流:
    return new StreamableFile(file.stream, {
      type: 'application/pdf',
      headers: {
        'Transfer-Encoding': 'chunked',
      },
    });
    
  • 切换到Fastify框架:Fastify处理HTTP流的性能比Express高出不少,若当前使用Express可考虑迁移。
  • 启用Gzip压缩:对于文本类或可压缩文件,在Nest中启用压缩中间件减少传输数据量:
    import { CompressionMiddleware } from '@nestjs/platform-express';
    
    app.use(CompressionMiddleware());
    

4. 开启S3传输加速

在S3控制台开启目标存储桶的传输加速功能,然后修改S3Client配置:

new S3Client({
  // ...其他原有配置
  useAccelerateEndpoint: true,
});

这会让S3请求通过CloudFront全球边缘节点传输,显著提升跨区域下载速度。

5. 错误处理优化

避免直接抛出原始错误,改为返回标准化HTTP错误,同时减少不必要的错误对象创建开销:

catch (err) {
  throw new HttpException(`下载失败: ${err.message}`, HttpStatus.INTERNAL_SERVER_ERROR);
}

内容的提问来源于stack exchange,提问作者Mansouri Rayen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:46:33