API网关POST方法在测试期间有效,但不适用于邮递员

时间:2019-03-26 09:48:22

标签: api aws-lambda aws-api-gateway

我会尽力清楚地解释我的问题。

我有一个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":"",
}

那解释了错误,但是我不明白为什么当我用邮递员发送它(不为空,使用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}"`));
    }
};

3 个答案:

答案 0 :(得分:1)

这是因为从AWS Lambda的控制台进行测试时,您正在发送实际期望的JSON。但是,当从API Gateway调用它时,事件看起来就不同了。

您必须访问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中的项目:

enter image description here

这是我的邮递员要求:

enter image description here

带有正确的标题:

enter image description here

在创建API网关时,我选中了Use Lambda Proxy integration框。我的API如下所示:

enter image description here

如果重现这些步骤,则应该可以正常工作。

答案 1 :(得分:1)

我遇到了完全相同的问题,对我来说,解决方案是部署api,以便通过Postman进行更改!

希望即使在一年之后,它也会有所帮助

答案 2 :(得分:-1)

您需要部署您的Amazon API Gateway !!!我花了很长时间才弄清楚这一点,

Deploy API