十分钟搞定Nestjs上传文件到阿里云OSS

背景:nestjs生成文件后将文件上传到阿里云的oss,此处简化操作,放核心代码,生成excel后直接上传到阿里云oss。

这也是后台系统中常见的操作,现在开始十分钟教大家完成此项功能。

步骤:

  1. 生成excel
  2. 文件上传到阿里云: 使用oss sdk将文件Buffer上传的到oss
  3. 整合到Nestjs服务

先浏览下成果

1. 生成excel

先安装包pnpm i xlsx

生成excel, 这一步比较简单,可直接写在服务里

js 复制代码
import * as XLSX from 'xlsx';
import { Buffer } from 'buffer'; // 明确导入 Buffer

  // 创建Excel
  async createExcel({ sheetName = 'test1' }: any) {
    const users = [
      { id: 1, name: '张三2', age: 25, email: 'zhangsan@example.com' },
      { id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
      { id: 3, name: '王五', age: 28, email: 'wangwu@example.com' },
    ];
    const worksheet = XLSX.utils.json_to_sheet(users);
    // 新建表格
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
    const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' });
    return buffer as Buffer;
  }

2. 封装阿里云OSS上传工具函数

先安装包pnpm i ali-oss

在 util 中封装上传函数 oss.util.ts

js 复制代码
import * as OSS from 'ali-oss';

export class OssUtil {
  private static client: OSS | null = null;

  /**
   * 初始化,必须在应用启动时或首次使用是完成初始化
   * config: 阿里云配置
   */
  public static init(config: any): void {
    // 如果已初始化,跳过初始化
    if (this.client) return;
    // 从配置文件中取oss配置
    this.client = new OSS({
      region: config.region,
      accessKeyId: config.accessKeyId,
      accessKeySecret: config.accessKeySecret,
      bucket: config.bucket,
    });
  }

  /**
   * 获取 OSS 客户端实例,如果未初始化则抛出错误
   */
  private static getClient(): OSS {
    if (!this.client) {
      throw new Error('OSS 客户端未初始化,请先调用 OssUtil.initialize(config) 方法。');
    }
    return this.client;
  }

  /**
   * 上传文件 Buffer 到阿里云 OSS
   * @param objectName - 在 OSS 中的目标路径和文件名 (e.g., 'exports/report_timestamp.xlsx')
   * @param buffer - 要上传的文件内容的 Node.js Buffer
   * @returns 包含文件 URL 的 Promise
   */
  public static async uploadBuffer(objectName: string, buffer: Buffer): Promise<string> {
    const client = this.getClient();

    const options: OSS.PutObjectOptions = {
      // 如果需要,可以在这里设置 Content-Type, 例如 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
      // headers: { 'Content-Type': 'application/octet-stream' }, 
    };

    try {
      const result = await client.put(objectName, buffer, options);
      console.log('==== oss.util result: ', result);
      // result.url 是文件在 OSS 上的完整访问地址
      return result.url;
    } catch (error) {
      console.error(`[OSS ERROR] 上传文件 ${objectName} 失败:`, error);
      throw new Error(`文件上传到 OSS 失败: ${error.message}`);
    }
  }
}

2.1. 初始化OssUtil

在main.ts中初始化,然后才能在业务服务中使用

js 复制代码
import { OssUtil } from './util/oss.util';

async function bootstrap() {
  // 初始化oss
  const ossConfig = {
    region: configService.get<string>('ALIYUN_OSS_REGION'),
    accessKeyId: configService.get<string>('ALIYUN_OSS_ACCESS_KEY_ID'),
    accessKeySecret: configService.get<string>('ALIYUN_OSS_ACCESS_KEY_SECRET'),
    bucket: configService.get<string>('ALIYUN_OSS_BUCKET'),
  };
  OssUtil.init(ossConfig);

}
bootstrap();

在业务服务中使用,简单示例

csharp 复制代码
  // 3. 上传到 OSS
  const ossResult = await OssUtil.uploadBuffer(objectName, excelBuffer);

3. 整合Service,完成最终上传

在红果服务中使用生成excel+上传阿里云

js 复制代码
import * as XLSX from 'xlsx';
import { Buffer } from 'buffer'; // 明确导入 Buffer
import { OssUtil } from 'src/util/oss.util';

@Injectable()
export class HongguoService {
  // 业务
  async zyf_create_short_url(params: any) {
    // 1. 创建Excel
    const excelBuffer = await this.createExcel({ sheetName: 'test1' });
    console.log('===excelBuffer: ', excelBuffer);

    // 2. 上传到 OSS
    const timestamp = new Date().getTime();
    const fileName = `node/test_${timestamp}.xlsx`;
    const ossResult = await OssUtil.uploadBuffer(fileName, excelBuffer);
    console.log('==== ossResult: ', ossResult);

    return {
      ossResult
    }
  }

  // 创建Excel
  async createExcel({ sheetName = 'test1' }: any) {
    const users = [
      { id: 1, name: '张三2', age: 25, email: 'zhangsan@example.com' },
      { id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
      { id: 3, name: '王五', age: 28, email: 'wangwu@example.com' },
    ];
    const worksheet = XLSX.utils.json_to_sheet(users);
    // 新建表格
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
    const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' });
    return buffer as Buffer;
  }
  
}

搞定,控制器就不演示了,直接调这个服务即可。

对你有帮助的话请一键三连哈

相关推荐
嘟嘟MD5 小时前
程序员副业 | 2025年12月复盘
后端·创业
..过云雨7 小时前
17-2.【Linux系统编程】线程同步详解 - 条件变量的理解及应用
linux·c++·人工智能·后端
南山乐只8 小时前
【Spring AI 开发指南】ChatClient 基础、原理与实战案例
人工智能·后端·spring ai
全栈前端老曹8 小时前
【前端路由】Vue Router 嵌套路由 - 配置父子级路由、命名视图、动态路径匹配
前端·javascript·vue.js·node.js·ecmascript·vue-router·前端路由
努力的小雨9 小时前
从“Agent 元年”到 AI IDE 元年——2025 我与 Vibe Coding 的那些事儿
后端·程序员
源码获取_wx:Fegn08959 小时前
基于springboot + vue小区人脸识别门禁系统
java·开发语言·vue.js·spring boot·后端·spring
wuxuanok10 小时前
Go——Swagger API文档访问500
开发语言·后端·golang
用户214118326360210 小时前
白嫖Google Antigravity!Claude Opus 4.5免费用,告别token焦虑
后端
爬山算法11 小时前
Hibernate(15)Hibernate中如何定义一个实体的主键?
java·后端·hibernate