我会尽力清楚地解释我的问题。
我有一个API,该API使用在Node.js中编写的lambda函数在DynamoDB中编写内容。当我在AWS控制台中调用它时,API会按预期工作。我发送这样的尸体:
{
"user-id":"4dz545zd",
"name":"Bush",
"firstname":"Gerard",
}
然后在我的dynamoDB表中创建条目。但是,当我用Postman调用相同的API(新部署)时,出现此错误:
{
"statusCode": "400",
"body": "One or more parameter values were invalid: An AttributeValue may not contain an empty string",
"headers": {
"Content-Type": "application/json"
}
}
当我检查cloudwatch为什么失败时,我看到:转换之前的方法请求正文:[二进制数据]
这很奇怪,因为我发送了带有两个标头的JSON:
Content-Type:application/json
Accept:application/json
然后在cloudwatch中,我看到正在处理的是:
{
"user-id":"",
"name":"",
"firstname":"",
}
多数民众赞成在解释该错误,但是我不明白为什么当我使用 Postman 发送它(不为空,使用json格式)时,它仍然将其作为“二进制”数据发送,因此没有被我的映射规则处理(因此,lambda使用一个空的json处理它):
#set($inputRoot = $input.path('$'))
{
"httpMethod": "POST",
"body": {
"TableName": "user",
"Item": {
"user-id":"$inputRoot.get('user-id')",
"name":"$inputRoot.get('name')",
"firstname":"$inputRoot.get('firstname')",
}
}
}
先感谢你 !
编辑:我正在添加lambda代码功能
'use strict';
console.log('Function Prep');
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();
exports.handler = (event, context, callback) => {
const done = (err, res) => callback(null, {
statusCode: err ? '400' : '200',
body: err ? err.message : res,
headers: {
'Content-Type': 'application/json'
},
});
switch (event.httpMethod) {
case 'DELETE':
dynamo.deleteItem(event.body, done);
break;
case 'HEAD':
dynamo.getItem(event.body, done);
break;
case 'GET':
if (event.queryStringParameters !== undefined) {
dynamo.scan({ TableName: event.queryStringParameters.TableName }, done);
}
else {
dynamo.getItem(event.body, done);
}
break;
case 'POST':
dynamo.putItem(event.body, done);
break;
case 'PUT':
dynamo.putItem(event.body, done);
break;
default:
done(new Error(`Unsupported method "${event.httpMethod}"`));
}
};
这是因为从AWS Lambda的控制台进行测试时,你正在发送实际期望的JSON。但是,当从API网关调用此事件时,该事件看起来有所不同。
你必须访问该event.body
对象才能获取JSON,但是主体是Stringified JSON,这意味着你必须首先对其进行解析。
你没有指定编码语言,但是如果你使用的是NodeJS,则可以像下面这样解析主体:
JSON.parse(event.body)
。
如果你使用的是Python,则可以执行以下操作:
json.loads(event["body"])
如果你使用任何其他语言,建议你查找如何从给定的String解析JSON。
这满足了你的需求。
这是来自API Gateway的事件,如下所示:
{
"path": "/test/hello",
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, lzma, sdch, br",
"Accept-Language": "en-US,en;q=0.8",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
"Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
"X-Forwarded-For": "192.168.100.1, 192.168.1.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"pathParameters": {
"proxy": "hello"
},
"requestContext": {
"accountId": "123456789012",
"resourceId": "us4z18",
"stage": "test",
"requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
"identity": {
"cognitoIdentityPoolId": "",
"accountId": "",
"cognitoIdentityId": "",
"caller": "",
"apiKey": "",
"sourceIp": "192.168.100.1",
"cognitoAuthenticationType": "",
"cognitoAuthenticationProvider": "",
"userArn": "",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
"user": ""
},
"resourcePath": "/{proxy+}",
"httpMethod": "GET",
"apiId": "wt6mne2s9k"
},
"resource": "/{proxy+}",
"httpMethod": "GET",
"queryStringParameters": {
"name": "me"
},
"stageVariables": {
"stageVarName": "stageVarValue"
},
"body": "'{\"user-id\":\"123\",\"name\":\"name\", \"firstname\":\"firstname\"}'"
}
编辑
在评论中进一步讨论之后,另一个问题是你正在使用DynamoDB API而不是DocumentClient API。使用DynamoDB API时,必须指定对象的类型。另一方面,DocumentClient消除了这种复杂性。
我还对你的代码进行了一些重构(为简单起见,此刻仅处理POST),因此你可以使用async / await
'use strict';
console.log('Function Prep');
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
switch (event.httpMethod) {
case 'POST':
await dynamo.put({TableName: 'users', Item: JSON.parse(event.body)}).promise();
break;
default:
throw new Error(`Unsupported method "${event.httpMethod}"`);
}
return {
statusCode: 200,
body: JSON.stringify({message: 'Success'})
}
};
这是DynamoDB中的项目:
这是我的 Postman 要求:
带有适当的标题:
创建API网关时,我选中了框Use Lambda Proxy integration
。我的API如下所示:
如果重现这些步骤,则应该可以正常工作。
感谢您的快速回复。但是当我从API网关和lambda测试对其进行测试时,它可以工作。我应该在lambda函数中解析吗?这是我修改后的代码:dynamo.putItem(JSON.parse(event.body),done); 休息; 案例'PUT':dynamo.putItem(JSON.parse(event.body),完成); 休息;
您能用相关代码编辑您的问题吗?
通过查看您的问题,它似乎无法在API Gateway中运行。当您通过Postman调用URL时,您将触发API网关,而API网关将依次调用您的Lambda函数
而且我知道为什么它不起作用。这是因为您使用的是DynamoDB而不是DocumentClient。我将相应地编辑答案,但是请发布您的代码,以防万一我遗漏任何东西。
确实可以!我尝试了所有的POT和PUT方法,并且在API Gateway测试中,它可以正常工作