如何将在 Lambda 上使用 NodeJS 丰富的对象返回到 API POST 请求
Posted
技术标签:
【中文标题】如何将在 Lambda 上使用 NodeJS 丰富的对象返回到 API POST 请求【英文标题】:How can I return an object enriched using NodeJS on Lambda to an API POST request 【发布时间】:2019-01-26 00:06:21 【问题描述】:我正在使用 Lambda/NodeJS 在 AWS 上进行开发。为了响应 POST 请求,我试图返回一个数据对象,我用预签名的 URL 来丰富它以访问 S3 上的图像。问题是返回数据,因此它实际上是作为 API 的响应返回的。我知道这是一个异步问题,但到目前为止还没有解决它。非常感谢任何帮助。
我有以下代码:
docClient.query(dbparams, function (err, data)
if (err)
console.log(err);
_response = buildOutput(500, err);
return callback(_response, null);
else
dataObj = data.Items;
var createOutput = function (callback)
async.forEach(dataObj, function (item, callback)
setObjectUrl(item, function (err, data)
if (err)
console.log(err);
return callback(undefined, data);
);
);
;
createOutput(function (err, data)
if (err)
console.log(err);
);
_response = buildOutput(200, data);
return callback(null, _response);
);
function setObjectUrl(data, callback)
var s3params =
Bucket: s3Bucket,
Key: 'avatars/' + data.username + '.jpg'
;
S3.headObject(s3params, function (err, metadata)
if (err && err.code === 'NotFound')
//console.log('geen url voor deze gebruiker gevonden');
else
data["url"] = S3.getSignedUrl('getObject', s3params);
return callback(data);
);
function buildOutput(statusCode, data)
let _response =
statusCode: statusCode,
headers:
"Access-Control-Allow-Origin": "*"
,
body: JSON.stringify(data)
;
return _response;
【问题讨论】:
请格式化您的代码。 抱歉,刚刚做了。 不幸的是我不能分享数据,但我可以解释一下我得到的输出。我从从 docClient.query(dbparams, function (err, data) 回调的数据对象中得到响应。我想要的是来自 return callback(data); 在函数 setObjectUrl(data, callback) 中的数据. 【参考方案1】:这就是我最终解决它的方法。感谢您的帮助。
const AWS = require('aws-sdk');
const util = require('util');
// Create reference to S3 client
var S3 = new AWS.S3(
region: 'XXXXXXXXXXXX'
apiversion: '2006-03-01'
);
// Lambda provided credentials
let creds = new AWS.EnvironmentCredentials('AWS');
const dynamoConfig =
credentials: creds,
region: process.env.AWS_REGION
;
const dynamoDB = new AWS.DynamoDB.DocumentClient(dynamoConfig);
const dynamoDBGetAsync = util.promisify(dynamoDB.query).bind(dynamoDB);
// some variables we need
const ddbTable = 'database';
var _response;
var s3Bucket = 'photo-bucket';
module.exports.handler = async (event, context, callback) =>
if (event.resource === '/' && event.httpMethod === "GET")
const username = event.queryStringParameters.userid;
var params =
TableName: ddbTable,
IndexName: 'userid-index',
KeyConditionExpression: "#uid = :uid",
ExpressionAttributeNames:
"#uid": "userid"
,
ExpressionAttributeValues:
":uid": username
;
let result= await dynamoDBGetAsync(params);
for (let item of result.Items)
if (item.username !== undefined || null)
item.url = await getObjectUrl(item);
_response = buildOutput(200, result);
return callback(null, _response);
;
function getObjectUrl(data)
console.log("Data: " +JSON.stringify(data));
const s3params =
Bucket: s3Bucket,
Key: 'avatars/' + data.username + '.jpg'
;
return new Promise((resolve, reject) =>
S3.headObject(s3params, function (err, metadata)
console.log('parameters: ' + JSON.stringify(s3params));
if (err && err.code === 'NotFound')
console.log(JSON.stringify(err));
else
const signedUrl = S3.getSignedUrl('getObject', s3params);
console.log(signedUrl);
resolve(signedUrl);
);
);
function buildOutput(statusCode, data)
let _response =
statusCode: statusCode,
headers:
"Access-Control-Allow-Origin": "*"
,
body: JSON.stringify(data)
;
return _response;
【讨论】:
【参考方案2】:所有异步调用完成后,您需要调用 lambda 的回调。有一些不同的选项可以修复您的代码,但我建议使用 Promise 和 async/await。这不仅可以使您的代码正常工作,还可以使其更具可读性并有助于避免回调地狱。
您需要将您的 S3 调用封装在 Promise 中:
function getObjectUrl(data)
const s3params =
Bucket: s3Bucket,
Key: 'avatars/' + data.username + '.jpg'
;
return new Promise((resolve, reject) =>
S3.headObject(s3params, function (err, metadata)
if (err)
//handle error
else
const signedUrl = S3.getSignedUrl('getObject', s3params);
resolve(signedUrl);
);
);
之后你只需要循环调用你的promisified函数:
for(let item of data.Items)
item.url = await getObjectUrl(data);
别忘了让你的主函数异步并配置你的 lambda 以使用 NodeJS 8.10
【讨论】:
感谢您的及时回复。当我在带有 NodeJS 8.10 的 Lambda 中使用此代码时,出现解析错误:在等待之后立即出现意外令牌 getObjectUrl。我已经使我的主要功能异步。笔记。我一直在尝试使用 aync await 解决问题,但遇到了同样的问题……有什么建议吗? 这很奇怪,async/await 在 lambda 上与 NodeJS 8.10 完美配合。你能用你的异步 lambda 处理程序发布你的代码部分吗? Sasha,我认为问题在于我必须使 docClient.query 异步,而不是主要,因为这是 for 循环所在的位置。试图弄清楚如何使 docClient.query 异步... 这可能是不可能的,因为它具有固有的异步性质。 哦,我明白了。您想要做的不是使 docClient 异步,它已经是异步的。您实际需要做的是使该方法被承诺。在 nodejs 8 中有一种简单而干净的方法: const util = require('util');常量 fs = 要求('fs'); const stat = util.promisify(fs.stat);结果 = 等待 stat('.');以上是关于如何将在 Lambda 上使用 NodeJS 丰富的对象返回到 API POST 请求的主要内容,如果未能解决你的问题,请参考以下文章
使用 AWS Lambda (NodeJS) 创建 AWS AppSync
如何从 NodeJS 和 Lambda 在 EMR Hive 上运行查询
AWS Lambda - 下载文件,并在同一个函数中使用它 - nodejs