无法将更新后的响应从AWS Lambda中的回调函数发送到API网关

时间:2018-09-17 15:21:20

标签: node.js aws-lambda aws-api-gateway

我创建了一个API网关,该网关路由到AWS Lambda函数(节点8.10)。 Lambda函数向第三方API发出POST请求,并且应将响应(状态和消息)返回给API GATEWAY。发生的事情是,我能够成功调用第三方API(它是一个发布请求,因此我可以检查Lambda是否正在执行其工作),但是当我将响应发送回API GATEWAY时,它无法发送更新的响应。

这样做的原因是Lambda几乎立即调用了callback(null,response),而来自第三方API的响应则稍后出现,因此响应对象稍后被更新(我可以通过控制台日志确认)。我已经在回调函数中编写了一个回调(空,响应),如从所附代码段中可以看到的那样,但似乎API GATEWAY考虑了最早的回调响应。如何确保LAMBDA函数仅发送更新的响应。以下是附带的代码:

const https = require('https');

exports.handler = async (event, context, callback) => {

  var body = JSON.parse(event.body);
  var postData = JSON.stringify(body);
  const options = {
      method: 'POST',
      hostname: app_url
      path: path_value
      port: 443,
      headers: {
          'accept': 'application/json',
          'Content-Type': 'application/json',
          'Content-Length': postData.length,
          'Authorization': auth_token_value
      }
  };

  var response = {};
  var dataStr = "";

  const req = https.request(options, (res) => {
      response.statusCode = res.statusCode;
      response.headers = res.headers;

      res.on('data', (d) => {
          dataStr += d;
      });

      res.on('end', () => {
          response.body = dataStr;
          console.log(response);
          callback(null, response);
      });
  });

  req.write(postData);
  req.end();

  console.log(response);
  callback(null, response);
}

4 个答案:

答案 0 :(得分:1)

最终的工作代码如下。不过,我仍然需要弄清楚res.headers这部分。

const https = require('https');

exports.handler = (event, context, callback) => {

    var body = JSON.parse(event.body);
    var postData = JSON.stringify(body);
    const options = {
        method: 'POST',
        hostname: app_url,
        path: path_value,
        port: 443,
        headers: {
            'accept': 'application/json',
            'Content-Type': 'application/json',
            'Content-Length': postData.length,
            'Authorization': auth_token_value
        }
    };

    var response = {};
    var dataStr = "";

    const req = https.request(options, (res) => {
        response.statusCode = res.statusCode;
        response.headers = {}; // TODO: should be res.headers ideally

        res.on('data', (d) => {
            dataStr += d;
        });

        res.on('end', () => {
            response.body = dataStr;
            console.log(response);
            callback(null, response);
        });
    });

    req.write(postData);
    req.end();
}

答案 1 :(得分:0)

您似乎需要删除最后两行(console.log和对callback函数的调用),否则在对您的请求的响应到达之前,它们将被同步调用。你。

答案 2 :(得分:0)

简短的回答:由AdrianT提供。删除最后两行。

长答案:当您调用http.request(在req.end()中)时,函数调用是在异步模式下进行的。这意味着该函数作为参数接收的所有内容都将在将来的某个时刻执行。

但是在异步调用(fire和 forget )之后,该函数在下一行继续执行。在您的示例中,下一行是console.log,然后是callback(null,response)。可能这两行是在网络中断成为通往第三方服务器的路径的第一部分之前很长时间(以cpu时间)执行的。

通过回调,lambda的事件源将被告知lambda调用的结果。即使函数继续执行(等待事件循环中仍然打开的事件),也已经发送了函数返回。因此,事件源,在这种情况下,API Gateway可以理解该功能已经完成了他的工作,并将其转发给调用者。

答案 3 :(得分:0)

由于整个混乱是由于节点脚本的异步性质,并且由于在我的小lambda函数中使用异步方式执行操作而没有任何优势,因此我最终用Python编写了相同的代码(使用{{1 }}模块)。现在一切正常。但是我仍然想知道如何在此处使用节点脚本解决问题。