node.js - 使用预签名 URL 和 AWS Lambda 函数(使用 Angular 8、Node.js 和 Netlify)将文件上传到 AWS S3 存储桶
问题描述
最初,我有一个 Angular 8+ 应用程序,其中包含一个上传表单和一些生成 AWS 预签名 URL 的代码,这些 URL 用于将上传表单中选择的文件上传到 AWS S3 存储桶。代码看起来像这样:
const AWS = require('aws-sdk');
import { Component, OnInit, } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../environments/environment';
@Component({
selector: 'app-upload-page',
templateUrl: './upload-page.component.html',
styleUrls: ['./upload-page.component.scss']
})
export class UploadComponent implements OnInit {
private S3: any;
private UPLOAD_FOLDER = 'test/';
public file: File;
constructor(private http: HttpClient) {}
ngOnInit(): void {
AWS.config.update({
accessKeyId: environment.amazon.s3.secretAccessId,
secretAccessKey: environment.amazon.s3.secretAccessKey,
region: environment.amazon.s3.region,
signatureVersion: environment.amazon.s3.signatureVersion
});
this.S3 = new AWS.S3();
}
// Triggered when clicking the upload button after attaching a file to <input type="file"/>
public async onUpload(): Promise<void> {
try {
const params = this.buildUploadParams(environment.amazon.s3.bucketname, this.UPLOAD_FOLDER + this.file.name, this.file.type, 120);
const preSignedGetUrl = this.S3.getSignedUrl('putObject', params);
await this.upload(preSignedGetUrl, this.file); // this.file is the body
this.file = null;
} catch (error) {
console.error(error);
}
}
// Triggered when selecting a file
public onChange($event: any): void {
const files = $event.srcElement.files;
this.file = files[0];
}
// Triggers the presigned url and attaches this.file to body
private upload(url: string, body: any): Promise<any> {
return new Promise((resolve, reject) => {
this.http.put(url, body).toPromise()
.then(res => resolve(res), (error: any) => reject(error));
});
}
// Builds params required to generate presigned urls
private buildUploadParams(bucket: string, key: string, contentType: string, expires: number): any {
return {
Bucket: bucket,
Key: key,
ContentType: contentType,
ACL: 'bucket-owner-full-control',
Expires: expires
};
}
}
此代码工作正常,但我想删除从客户端(Angular 8+)生成预签名 URL 到 Node.js 应用程序中的 AWS Lambda 函数的责任。
所以我添加了一个新环境。我通过 Netlify 部署的 Node.js 实例,因此我可以通过 URL 轻松访问 AWS Lambda 函数,例如https://my-url.netlify.com/.netlify/functions/upload?file= ' + 文件。
这就是我的 AWS Lambda 函数在 Node.js 实例的 functions/upload.js 文件中的样子:
// Below is the content of the upload.js file
const AWS = require('aws-sdk');
const request = require('request');
// AWS credentials
const S3_ACCESS_KEY_ID = 'MY_ACCESS_KEY_ID';
const S3_SECRET_ACCESS_KEY = 'MY_SECRET_ACCESS_KEY';
const BUCKET_NAME = 'MY_BUCKET_NAME';
const UPLOAD_FOLDER = 'test/';
AWS.config.update({
accessKeyId: S3_ACCESS_KEY_ID,
secretAccessKey: S3_ACCESS_ACCESS_KEY,
region: 'eu-west-1',
signatureVersion: 'v4'
});
const s3 = new AWS.S3();
function buildUploadParams(bucket, key, contentType, expires) {
return {
Bucket: bucket,
Key: key,
ContentType: contentType,
ACL: 'bucket-owner-full-control',
Expires: expires
}
}
function upload(url, body) {
return new Promise((resolve, reject) => {
request({ method: 'PUT', url: url, body: body }, (error, response, body) => {
if (error) {
return reject(error);
}
if (response.statusCode !== 200) {
return reject(body.error_description);
}
resolve();
});
});
}
function response (code, body) {
return {
'statusCode': code,
'headers': { 'Access-Control-Allow-Origin': '*' },
'body': body,
'isBase64Encoded': false
}
}
async function uploadFile(file) {
const params = buildUploadParams(BUCKET_NAME, UPLOAD_FOLDER, file.type, 120);
const preSignedGetUrl = s3.getSignedUrl('putObject', params);
await upload(preSignedGetUrl, file);
return 'Successfully uploaded file';
}
// AWS Lambda Function
exports.handler = async (event, context, callback) => {
// Should I pass file content with the query and get it like this: event.queryStringParameters['file'];
const file = event.queryStringParameters['file'];
callback(null, response(200, uploadFile(file)));
};
然后我可以向 Netlify URL 发出 HTTP POST 请求,在其中我将来自 Angular 8+ 客户端的文件作为参数传递给 Netlify URL,但是你不能真正将文件对象 [File object] 作为 URL 参数传递,所以我该如何进行?
可能有助于我弄清楚如何将 this.file 从 Angular 传输到 Node.js AWS Lambda 函数的问题:
在使用预签名 URL 时,而不是添加整个 this.file 对象,我可以只使用文件内容吗?如果是,是什么形式?
总的来说,您对这种方法有何看法?
是否有替代方法(要求:我仍然需要使用 Angular、Node.js 和 Netlify)
解决方案
推荐阅读
- c# - 用组合框替换文本框时遇到 JSON 错误
- linux - 在不同进程的地址空间中映射页面
- arrays - 遍历 React.js 中的嵌套对象
- bash - 获取 bash 变量的文字值,无需全局扩展或其他更改
- github - 使用 git 作为 helm repo 抛出“似乎不是 gzip 压缩的存档;得到 'text/html; charset=utf-8'”
- mongodb - 使用 asyncData() 从数据库中获取用户
- c# - 如何使用 XPath 按文本查找元素
- javascript - 在对象数组中插入新元素并对数组进行排序
- swift - 查看 NSDictionary 键/值对中是否存在作为 Swift 4 中 NSMutableArray 元素的值
- google-bigquery - 在 Stackdriver Logging 中看不到 BigQuery 上的 JDBC 驱动程序查询