准备:
- OSS对象存储服务器
- 域名(如果是练习的话,域名建议购买香港域名) 阿里云官网
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,然后上传的图片就可以通过这个二级域名进行访问.
手动创建一个二级域名
4. 测试
上传
访问