在开发无服务器应用的时候,通过纯手工方式创建各种资源的话,效率会非常低,因此需要借助一些框架来提高开发效率。下面介绍如何在serverless中开发S3 API(Lambda)。

serverless教程
S3公共模块
增加文件api/common/s3/S3.js:
Javascript
const AWS = require('aws-sdk');
AWS.config.update({ region: "eu-west-1" });
const s3Client = new AWS.S3();
const S3 = {
async get(params) {
let obj = await s3Client.getObject(params).promise();
if (!obj) {
throw Error('Failed to get file from S3 bucket.');
}
if (params.Key.endsWith('.json') || params.Key.endsWith('.txt')) {
obj = obj.Body.toString();
}
return obj;
},
async write(params) {
const newObj = await s3Client.putObject(params).promise();
if (!newObj) {
throw Error('there was an error writing the file');
}
return newObj;
},
};
module.exports = S3;
获取文件的Lambda handler
api/files/getFile.js:
Javascript
const Responses = require('../common/Responses');
const S3 = require('../common/s3/S3');
const bucket = process.env.bucketName;
exports.handler = async event => {
if (!event.pathParameters || !event.pathParameters.fileName) {
return Responses.HTTP_RESPONSE(400, { message: 'missing the fileName from the path' });
}
let fileName = event.pathParameters.fileName;
const params = {
Bucket: bucket,
Key: fileName,
};
const file = await S3.get(params).catch(err => {
console.log('error in S3 get', err);
return null;
});
if (!file) {
return Responses.HTTP_RESPONSE(500, { message: 'Failed to get file from S3 bucket.' });
}
return Responses.HTTP_RESPONSE(200, { file });
};
文本文件上传的Lambda handler
Javascript
const Responses = require('../common/Responses');
const S3 = require('../common/s3/S3');
const bucket = process.env.bucketName;
exports.handler = async event => {
if (!event.pathParameters || !event.pathParameters.fileName) {
return Responses.HTTP_RESPONSE(400, { message: 'fileName is missing in the path.' });
}
const fileName = event.pathParameters.fileName;
const obj = JSON.parse(event.body);
const params = {
Bucket: bucket,
Key: fileName,
Body: JSON.stringify(obj),
};
const newObj = await S3.write(params).catch(err => {
console.log('error in S3 write', err);
return null;
});
if (!newObj) {
return Responses.HTTP_RESPONSE(500, { message: 'Failed to upload file to S3.' });
}
return Responses.HTTP_RESPONSE(200, { newObj });
};
二进制(Base64)格式文件上传
对应的S3操作
TypeSript
async writeBinary(bucketName: string, fileName: string, buffer: Buffer, contentType: string) {
const params = {
Bucket: bucketName,
Key: fileName,
Body: buffer,
ContentType: contentType,
};
const newObj = await s3Client.putObject(params).promise();
if (!newObj) {
throw Error('there was an error writing the file');
}
return newObj;
}
二进制大文件上传
当上传大文件的时候,就不太适合使用Lambda了,这个时候可以使用AWS S3的服务。在S3中,有一个方法叫做getPreSignedUrl,会生成一个上传URL,包含用户登录相关的信息。这个URL是有时效的。在客户端可以调用API获取一个这样的URL,然后发送文件上传请求到这个URL。
TypeScript
import { APIGatewayProxyEvent } from 'aws-lambda';
import Responses from './common/Responses';
import Identifier from './common/Identifier';
import S3 from './common/S3';
export const handler = async (event: APIGatewayProxyEvent) => {
try {
const userInput = JSON.parse(event.body || '{}');
if (!userInput.mime || !userInput.fileExtension) {
return Responses.HTTP_Response(400, {
message: 'User input error, expect mime and fileExtension from the request body.',
});
}
const s3Bucket = process.env.YOUR_BUCKET as string;
const uuid = Identifier.long_identifer();
const url = await S3.getPreSignedUrl(s3Bucket, `${uuid}.${userInput.fileExtension}`, userInput.mime);
return Responses.HTTP_Response(200, {
uploadUrl: url,
});
} catch (error) {
console.log('error', error);
return Responses.HTTP_Response(500, { message: 'Error occured while uploading file' });
}
};
serverless.yml
Javascript
service: service-07-api-s3
provider:
name: aws
region: eu-west-1
runtime: nodejs14.x
lambdaHashingVersion: 20201221
profile: default
iamRoleStatements:
- Effect: Allow
Action:
- s3:*
Resource: '*'
environment:
bucketName: ${self:custom.bucketName}
custom:
bucketName: lcoding-demo-bucket
resources:
Resources:
TestBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.bucketName}
functions:
getFile:
handler: api/files/getFile.handler
events:
- http:
path: get-file/{fileName}
method: GET
cors: true
uploadFile:
handler: api/files/uploadFile.handler
events:
- http:
path: upload-file/{fileName}
method: POST
cors: true
plugins:
- serverless-webpack
package:
individually: true