上传文件到aws 的s3
使用nodejs 生成上传的预签名,然后浏览器根据预签名上传文件到s3,我使用的nestjs框架
nestjs 代码示例
controller
js
@Controller('aws')
export class AwsController {
constructor(private readonly awsService: AwsService) {}
@Post('presignedUrl')
async getPresignedUrl(
@Body() body: GetPresignedUrlDto,
): Promise<{ url: string }> {
const url = await this.awsService.generatePresignedUrl(body);
return { url };
}
}
service
js
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { ConfigService } from '@nestjs/config';
import { GetPresignedUrlDto } from './dto/aws.dto';
@Injectable()
export class AwsService {
private readonly s3Client: S3Client;
private readonly bucketName: string;
constructor(private readonly configService: ConfigService) {
this.s3Client = new S3Client({
region: configService.get('AWS_REGION'), // 你的 AWS 区域
credentials: {
accessKeyId: configService.get('AWS_ACCESS_KEY_ID'), // 你的 AWS 访问密钥 ID
secretAccessKey: configService.get('AWS_SECRET_ACCESS_KEY'), // 你的 AWS 密钥
},
});
this.bucketName = configService.get('AWS_BUCKET_NAME'); // 你的 S3 存储桶名称
}
async generatePresignedUrl(body: GetPresignedUrlDto) {
const expiresInSeconds: number = 600;
const command = new PutObjectCommand({
Bucket: this.bucketName,
Key: body.key,
ContentType: body.contentType, // 设置 Content-Type,非常重要!
});
try {
const url = await getSignedUrl(this.s3Client, command, {
expiresIn: expiresInSeconds,
});
return url;
} catch (error) {
console.error('Error generating pre-signed URL', error);
throw error;
}
}
}
aws.dto
js
import { IsNotEmpty, IsString } from 'class-validator';
export class GetPresignedUrlDto {
@IsNotEmpty({ message: 'Key is required' })
@IsString({ message: 'Key must be a string' })
key: string;
@IsNotEmpty({ message: 'contentType is required' })
@IsString({ message: 'contentType must be a string' })
contentType: string;
}
vue上传文件
注意不要用FormData上传,postman 选择 binary
js
import { v4 as uuidv4 } from 'uuid'
import axios from 'axios'
async function uploadImgFun (file) {
const formObj = form.value
formObj.loading = true
form.value.img = ''
try {
const key = uuidv4()
const params = {
key,
contentType: file.file.type
}
const { data } = await getAwsPresignedUrl(params)
let url = data?.url.replace('https://xxxx.s3.us-east-1.amazonaws.com/', '/uploadS3/') //替换自己预签名url
await axios({
method: 'put',
url,
headers: {
'Content-Type': file.file.type
},
data: file.file,
timeout: 5 * 60 * 1000,
})
file.onSuccess()
form.value.img = `https://xxxxx.cloudfront.net/${key}` // 对应的s3域名或者 cloudfront域名
} catch (err) {
file.onError()
throw err
} finally {
formObj.loading = false
}
}
vite.config.js
js
['/uploadS3']: {
target: 'https://xxxx.s3.us-east-1.amazonaws.com',//替换自己的预签名地址,为了解决跨域
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^/uploadS3`), '')
},