【问题标题】:Store JSON request in DynamoDB with Lambda使用 Lambda 在 DynamoDB 中存储 JSON 请求
【发布时间】:2020-05-11 17:53:24
【问题描述】:

我的 Lambda 函数中有一个返回 json 的 http 请求。我正在使用 node.js。我想将该 json 作为对象保存在我的 DynamoDB 表中。

const http = require('https')
const AWS = require('aws-sdk');

AWS.config.update({region: "eu-west-1"});

exports.handler = async (event) => {
    return httprequest().then((data) => {
        //Parse JSON to objects

        // in this case not neccessary because it's already parsed.
        // data is already object

        // var arr_from_json = JSON.parse(data);

        //add Item to DynamoDB
        var params = {
            TableName: 'json',
            Item: {
                date: Date.now(),
                answer: data.answer,
                forced: data.forced,
                image: data.image
            }
        };

        var docClient = new AWS.DynamoDB.DocumentClient();

        docClient.put(params, function(err, data) {
            if (err) console.log(err);
            else console.log(data);
        });

        // Respond with JSON
        const response = {

            statusCode: 200,
            body: JSON.stringify(data),
        };
        return response;
    });
};

function httprequest() {
    return new Promise((resolve, reject) => {
        const options = {
            host: 'yesno.wtf',
            path: '/api',
            port: 443,
            method: 'GET'
        };
        const req = http.request(options, (res) => {
            if (res.statusCode < 200 || res.statusCode >= 300) {
                return reject(new Error('statusCode=' + res.statusCode));
            }
            var body = [];
            res.on('data', function (chunk) {
                body.push(chunk);
            });
            res.on('end', function () {
                try {
                    body = JSON.parse(Buffer.concat(body).toString());
                } catch (e) {
                    reject(e);
                }
                resolve(body);
            });
        });
        req.on('error', (e) => {
            reject(e.message);
        });
        // send the request
        req.end();
    });
}

JSON

{"answer":"no","forced":false,"image":"https://yesno.wtf/assets/no/8-5e08abbe5aacd2cf531948145b787e9a.gif"}

但是,它不会将对象存储在 DynamoDB 中。我能做些什么不同的事情?首先存储在 DynamoDB 中的部分是否正确?

【问题讨论】:

  • 您的 lambda 是否具有附加了 AmazonDynamoDBFullAccess 策略(或具有写入权限的自定义策略)的角色?
  • @Danziger 是的,我有一个具有读写权限的角色。
  • 您是否在 CloudWatch 中看到任何警报或错误?也许值得在您的代码中添加一些console.log() 以确保它实际上达到docClient.put()。此外,您可以尝试将其更改为 const data = await docClient.put(...).promise() 并且仅在 DynamoDB 操作完成后才发回响应,但我猜这应该没有任何区别。
  • @Danziger 感谢您抽出宝贵时间!我只是在 docClient.put(params, function(err, data) { 行之前放了一个 console.log(data) ,它显示在 CloudWatch 中。
  • @Danziger 问题可能是我在返回语句 return httprequest().then((data) =&gt; { 中使用了 put 函数吗?如果是这样,我该如何解决?

标签: javascript amazon-web-services lambda amazon-dynamodb


【解决方案1】:

首先,我假设表存在并且 lambda 具有正确的权限。否则,您将分别收到 Requested resource not foundnot authorized to perform: dynamodb:PutItem 错误。

您正在调用docClient.put(...),但随后只需从 lambda 返回响应,而无需等待 DynamoDB 的响应。如果您在发回响应之前等待 DynamoDB 的响应,它会按预期工作,您可以在下面使用 await 的示例中看到:

const AWS = require('aws-sdk');

// There's no need to re-instantiate this on each request:
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-west-1', apiVersion: 'latest' });    

function httprequest() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({
                answer: 'no',
                forced: false,
                image: 'https://yesno.wtf/assets/no/8-5e08abbe5aacd2cf531948145b787e9a.gif',
            });
        }, 2000);
    })
}

exports.handler = async (event) => {
    try {
        const data = await httprequest();

        const params = {
            Item: {
                date: Date.now(),
                answer: data.answer,
                forced: data.forced,
                image: data.image
            },

            TableName: 'json'
        };

        await docClient.put(params).promise();

        console.log('Document inserted.');

        return JSON.stringify(data);
    } catch(err) {
        console.log(err);

        return err;
    }
};

话虽如此,直觉上我会说如果达到docClient.put(...),那么无论如何都应该将文档插入到DynamoDB中,但看起来情况并非如此,至少在使用回调时不是这样。但是,如果您将其替换为 docClient.put(params).promise(),则会插入该文档,即使您不等待 DynamoDB 的响应也是如此。 docClient.put(params) 单独也行不通。

我认为这有点令人困惑/违反直觉,所以我创建了另一个问题,以了解更多关于为什么它的工作方式:

Why values are not inserted into DynamoDB unless calling `.promise()`?

【讨论】:

  • @incnnu 检查这个。我会做一些不同的事情,但如果执行达到docClient.put(params),那么我不明白为什么文档不会插入到 DynamoDB 中。
  • @Danzinger 非常感谢,您的代码运行良好!并感谢有用的提示!是的,我尝试了 return httprequest().then((data) =&gt; { 行上方的 put-function,它实际上会将项目存储在 DynamoDB 中,但将其放在该行下方不起作用。
  • @incnnu 我已经更新了答案,解释了哪些有效,哪些无效,但由于我仍然觉得这违反直觉,我还链接了我刚刚创建的另一个问题来查找找出它为什么会这样工作。
猜你喜欢
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-30
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
相关资源
最近更新 更多