NestJS - 如何将图像上传到 aws s3?
NestJS - How to upload image to aws s3?
我正在尝试在 NestJS API 上使用 multer-s3 将图像上传到 aws s3。我也试过 aws-sdk。我使用 FileInterceptor 和 UploadedFile 装饰器来捕获文件请求。到目前为止我所拥有的是:
// Controller
@Post()
@UseInterceptors(FileInterceptor('file', multerOptions))
uploadImage(@UploadedFile() file) {
console.log(file);
}
// multerOptions. multer.ts file
const configService = new ConfigService();
export const accessParams = {
accessKeyId: configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'),
region: configService.get('AWS_REGION'),
};
const imageMimeTypes = [
'image/jpg',
'image/jpeg',
'image/png',
'image/bmp',
];
AWS.config.update(accessParams);
export const s3 = new AWS.S3();
export const multerOptions = {
fileFilter: (req: any, file: any, cb: any) => {
const mimeType = imageMimeTypes.find(im => im === file.mimetype);
if (mimeType) {
cb(null, true);
} else {
cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);
}
},
storage: multerS3({
s3: s3,
bucket: configService.get('S3_BUCKET_NAME'),
acl: 'read-public',
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname })
},
key: (req: any, file: any, cb: any) => {
cb(null, `${Date.now().toString()}/${file.originalname}`);
},
contentType: multerS3.AUTO_CONTENT_TYPE
}),
};
这给了我以下错误:
{
"message": null,
"code": "InvalidArgument",
"region": null,
"time": "2020-04-24T05:34:19.009Z",
"requestId": "DH224C558HTDF8E3",
"extendedRequestId": "JKHKJH6877-LKJALDNC765llLKAL=",
"statusCode": 400,
"retryable": false,
"retryDelay": 6.790294010827713,
"storageErrors": []
}
有什么想法吗?谢谢。
你可以像这样创建一个控制器
import { Post, UseInterceptors, UploadedFile } from '@nestjs/common';
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
async upload(@UploadedFile() file) {
return await this.service.upload(file);
}
您的服务应如下所示
import { S3 } from 'aws-sdk';
import { Logger, Injectable } from '@nestjs/common';
@Injectable()
export class FileUploadService {
async upload(file) {
const { originalname } = file;
const bucketS3 = 'my-aws-bucket';
await this.uploadS3(file.buffer, bucketS3, originalname);
}
async uploadS3(file, bucket, name) {
const s3 = this.getS3();
const params = {
Bucket: bucket,
Key: String(name),
Body: file,
};
return new Promise((resolve, reject) => {
s3.upload(params, (err, data) => {
if (err) {
Logger.error(err);
reject(err.message);
}
resolve(data);
});
});
}
getS3() {
return new S3({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
}
}
使用打字和流:
import { ReadStream } from 'fs';
import * as AWS from 'aws-sdk';
import { PromiseResult } from 'aws-sdk/lib/request';
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TConfig, TStorageConfig } from '../../config';
@Injectable()
export class StorageService {
private S3: AWS.S3;
private BUCKET: string;
constructor(private configService: ConfigService<TConfig>) {
this.S3 = new AWS.S3({
// Your config options
accessKeyId: this.configService.get<TStorageConfig>('storage').accessKeyId,
secretAccessKey: this.configService.get<TStorageConfig>('storage').secretAccessKey,
endpoint: this.configService.get<TStorageConfig>('storage').endpoint,
s3ForcePathStyle: true,
signatureVersion: 'v4',
});
this.BUCKET = this.configService.get<TStorageConfig>('storage').bucket;
}
async getBlob(key: string): Promise<PromiseResult<AWS.S3.GetObjectOutput, AWS.AWSError>> {
const params = { Bucket: this.BUCKET, Key: key };
const blob = await this.S3.getObject(params).promise();
return blob;
}
async putBlob(blobName: string, blob: Buffer): Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>> {
const params = { Bucket: this.BUCKET, Key: blobName, Body: blob };
const uploadedBlob = await this.S3.putObject(params).promise();
return uploadedBlob;
}
// to get stream you can use file.createReadStream()
async putStream(key: string, stream: ReadStream): Promise<AWS.S3.PutObjectOutput> {
const file = await new Promise<AWS.S3.PutObjectOutput>((resolve, reject) => {
const handleError = (error) => {
reject(error);
};
const chunks: Buffer[] = [];
stream.on('data', (chunk: Buffer) => {
chunks.push(chunk);
});
stream.once('end', async () => {
const fileBuffer = Buffer.concat(chunks);
try {
const uploaded = await this.putBlob(key, fileBuffer);
resolve(uploaded);
} catch (error) {
handleError(new InternalServerErrorException(error));
}
});
stream.on('error', (error) => handleError(new InternalServerErrorException(error)));
});
return file;
}
}
我正在尝试在 NestJS API 上使用 multer-s3 将图像上传到 aws s3。我也试过 aws-sdk。我使用 FileInterceptor 和 UploadedFile 装饰器来捕获文件请求。到目前为止我所拥有的是:
// Controller
@Post()
@UseInterceptors(FileInterceptor('file', multerOptions))
uploadImage(@UploadedFile() file) {
console.log(file);
}
// multerOptions. multer.ts file
const configService = new ConfigService();
export const accessParams = {
accessKeyId: configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'),
region: configService.get('AWS_REGION'),
};
const imageMimeTypes = [
'image/jpg',
'image/jpeg',
'image/png',
'image/bmp',
];
AWS.config.update(accessParams);
export const s3 = new AWS.S3();
export const multerOptions = {
fileFilter: (req: any, file: any, cb: any) => {
const mimeType = imageMimeTypes.find(im => im === file.mimetype);
if (mimeType) {
cb(null, true);
} else {
cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);
}
},
storage: multerS3({
s3: s3,
bucket: configService.get('S3_BUCKET_NAME'),
acl: 'read-public',
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname })
},
key: (req: any, file: any, cb: any) => {
cb(null, `${Date.now().toString()}/${file.originalname}`);
},
contentType: multerS3.AUTO_CONTENT_TYPE
}),
};
这给了我以下错误:
{
"message": null,
"code": "InvalidArgument",
"region": null,
"time": "2020-04-24T05:34:19.009Z",
"requestId": "DH224C558HTDF8E3",
"extendedRequestId": "JKHKJH6877-LKJALDNC765llLKAL=",
"statusCode": 400,
"retryable": false,
"retryDelay": 6.790294010827713,
"storageErrors": []
}
有什么想法吗?谢谢。
你可以像这样创建一个控制器
import { Post, UseInterceptors, UploadedFile } from '@nestjs/common';
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
async upload(@UploadedFile() file) {
return await this.service.upload(file);
}
您的服务应如下所示
import { S3 } from 'aws-sdk';
import { Logger, Injectable } from '@nestjs/common';
@Injectable()
export class FileUploadService {
async upload(file) {
const { originalname } = file;
const bucketS3 = 'my-aws-bucket';
await this.uploadS3(file.buffer, bucketS3, originalname);
}
async uploadS3(file, bucket, name) {
const s3 = this.getS3();
const params = {
Bucket: bucket,
Key: String(name),
Body: file,
};
return new Promise((resolve, reject) => {
s3.upload(params, (err, data) => {
if (err) {
Logger.error(err);
reject(err.message);
}
resolve(data);
});
});
}
getS3() {
return new S3({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
}
}
使用打字和流:
import { ReadStream } from 'fs';
import * as AWS from 'aws-sdk';
import { PromiseResult } from 'aws-sdk/lib/request';
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TConfig, TStorageConfig } from '../../config';
@Injectable()
export class StorageService {
private S3: AWS.S3;
private BUCKET: string;
constructor(private configService: ConfigService<TConfig>) {
this.S3 = new AWS.S3({
// Your config options
accessKeyId: this.configService.get<TStorageConfig>('storage').accessKeyId,
secretAccessKey: this.configService.get<TStorageConfig>('storage').secretAccessKey,
endpoint: this.configService.get<TStorageConfig>('storage').endpoint,
s3ForcePathStyle: true,
signatureVersion: 'v4',
});
this.BUCKET = this.configService.get<TStorageConfig>('storage').bucket;
}
async getBlob(key: string): Promise<PromiseResult<AWS.S3.GetObjectOutput, AWS.AWSError>> {
const params = { Bucket: this.BUCKET, Key: key };
const blob = await this.S3.getObject(params).promise();
return blob;
}
async putBlob(blobName: string, blob: Buffer): Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>> {
const params = { Bucket: this.BUCKET, Key: blobName, Body: blob };
const uploadedBlob = await this.S3.putObject(params).promise();
return uploadedBlob;
}
// to get stream you can use file.createReadStream()
async putStream(key: string, stream: ReadStream): Promise<AWS.S3.PutObjectOutput> {
const file = await new Promise<AWS.S3.PutObjectOutput>((resolve, reject) => {
const handleError = (error) => {
reject(error);
};
const chunks: Buffer[] = [];
stream.on('data', (chunk: Buffer) => {
chunks.push(chunk);
});
stream.once('end', async () => {
const fileBuffer = Buffer.concat(chunks);
try {
const uploaded = await this.putBlob(key, fileBuffer);
resolve(uploaded);
} catch (error) {
handleError(new InternalServerErrorException(error));
}
});
stream.on('error', (error) => handleError(new InternalServerErrorException(error)));
});
return file;
}
}