Nestjs之上传阿里云OSS

99 阅读1分钟

准备:

  1. OSS对象存储服务器
  2. 域名(如果是练习的话,域名建议购买香港域名) 阿里云官网

image.png

1. 准备一个alii-oss.service.ts的服务类

// dev.yml
aliOss:
  //这些是通过开通OSS存储服务器之后下载的密钥信息
  accessKeyId: 'fnfsUIHioHIOHOIdshioad'        
  accessKeySecret: 'FSDfhsdfsDfSGjosdSDFsdfoi'
  region: 'oss-cn-hongkong' // 香港服务器是 hongkong  我一开始写的 xainggang 一直报错 
  bucket: 'app'             // OSS服务器的一个桶 bucket 名称

// index.ts
import * as yaml from 'js-yaml'
import { join } from 'path'
import { readFileSync } from 'fs'

const configFilenameObj = {
  development: 'dev',
  production: 'prod',
  test: 'test',
}

const env = process.env.NODE_ENV

export default () => {
  return yaml.load(readFileSync(join(__dirname, `./${configFilenameObj[env]}.yml`), 'utf8')) as Record<string, any>
}
  
  
// ali-oss.service.ts 
import { Injectable } from '@nestjs/common';
import * as OSS from 'ali-oss';
import { PassThrough } from 'stream';
import getConfig from '@/config/index';

@Injectable()
export class AliOssService {
  private client: any;
  constructor() {
    const configuration = getConfig();

    this.client = new OSS({
      accessKeyId: configuration.aliOss.accessKeyId,
      accessKeySecret: configuration.aliOss.accessKeySecret,
      region: configuration.aliOss.region,
      bucket: configuration.aliOss.bucket,
    });
  }

  async putOssFile(ossPath: string, file: any) {
    try {
      // 创建可读流
      const streamPassThrough = new PassThrough();
      streamPassThrough.end(file.buffer);

      // 使用文件流上传到阿里云 OSS
      const result = await this.client.putStream(ossPath, streamPassThrough);
      return result;
    } catch (e) {
      console.error(e);
      throw new Error('File upload failed');
    }
  }

  async calculatePostSignature(policy: any) {
    return this.client.calculatePostSignature(policy);
  }

  async getBucketInfo() {
    return this.client.getBucketInfo();
  }
}

2.在upload-image.service.ts中使用

// upload-image.controller.ts
import { Controller,  Post, UseInterceptors, UploadedFiles } from '@nestjs/common';
import { UploadImageService } from './upload-image.service';
import {  FilesInterceptor } from '@nestjs/platform-express';

@Controller('upload-image')
export class UploadImageController {
  constructor(private readonly uploadImageService: UploadImageService) { }
  @Post()
  @UseInterceptors(FilesInterceptor('files', 10)) // 第二个参数是上传文件的最大数量
  upload(@UploadedFiles() files: Express.Multer.File[]) {
    return this.uploadImageService.upload(files);
  }
}

//upload-image.service.ts
import { HttpStatus, Injectable } from '@nestjs/common';
import { AliOssService } from '@/common/uploadFileOSS/ali-oss.service';
import { InjectRepository } from '@nestjs/typeorm';
import { UploadImageEntity } from './entities/upload-image.entity';
import { Repository } from 'typeorm';
@Injectable()
export class UploadImageService {
    constructor(
        @InjectRepository(UploadImageEntity)
        private readonly uploadImageEntity: Repository<UploadImageEntity>,
        private readonly aliOssService: AliOssService,
      ) {}
      
    async upload(files: Express.Multer.File[]) {
    if (!files || files.length === 0) {
      return ResultData.fail(HttpStatus.BAD_REQUEST, '请上传文件');
    }

    if (files.length > 10) {
      return ResultData.fail(HttpStatus.BAD_REQUEST, '最多上传10个文件');
    }

    const modifiedUrls = [];

    for (const file of files) {
      const ossPath = `301-image/${file.originalname}`;
      const { res } = await this.aliOssService.putOssFile(ossPath, file);

      if (res.status === 200) {
        const { requestUrls } = res;

        for (let url of requestUrls) {
          // 这一步非必须,本意就是将OSS 的bucket地址换成自己的域名地址,为了好看、统一
          const modifiedUrl = url.replace(
            '返回的OSS地址网址',
            '替换你的自己的网站域名',
          );
          modifiedUrls.push(modifiedUrl);

          const existingImage = await this.uploadImageEntity.findOne({
            where: { url: modifiedUrl },
          });
          if (!existingImage) {
            await this.uploadImageEntity.save({ url: modifiedUrl });
          }
        }
      }
    }

    return {
      imageUrls: modifiedUrls,
    };
  }
}

3.域名解析(阿里云为例)

这里是为了配置上面的域名解析,一般我们会在自己的域名下解析图片,比如自己的域名叫www.example.com,可以设置一个二级域名比如image.example.com,然后上传的图片就可以通过这个二级域名进行访问.

image.png

手动创建一个二级域名

image.png

4. 测试

上传

image.png

访问

image.png