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

Node.js 无法将更新的响应从AWS Lambda中的回调函数发送到API网关,node.js,aws-lambda,aws-api-gateway,Node.js,Aws Lambda,Aws Api Gateway,我已经创建了一个API网关,它路由到AWS Lambda函数(节点8.10)。Lambda函数向第三方API发出POST请求,并应将响应(状态和消息)返回给API网关。所发生的事情是,我能够成功地调用第三方API(这是一个post请求,因此我可以检查Lambda是否正在执行其工作),但当我将响应发送回API网关时,它无法发送更新的响应 原因是Lambda几乎立即调用回调(null,response),而来自第三方API的响应来得晚,因此响应对象更新得晚(我可以通过控制台日志确认)。我已经在回调函

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

原因是Lambda几乎立即调用回调(null,response),而来自第三方API的响应来得晚,因此响应对象更新得晚(我可以通过控制台日志确认)。我已经在回调函数中编写了一个回调函数(null,response),这可以从所附的代码片段中看出,但API网关似乎考虑了最早的回调响应。如何确保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);
}

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

简短回答:由AdrianT给出。拆下最后两行

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

但就在异步调用(激发并忘记)之后,该函数将在下一行继续执行。在您的示例中,下一行是console.log,然后是callback(null,response)。这两行代码可能在网络传输到达第三方服务器路径的第一部分之前执行了很长时间(以cpu时间为单位)


通过回调,lambda的事件源被告知lambda调用的结果。即使函数继续执行(等待事件循环中仍然打开的事件),函数返回也已发送。因此,事件源(在本例中为API网关)了解函数已经完成了其工作,并将其转发给调用者。

由于整个混乱是由于节点脚本的异步性质造成的,并且我在我的小lambda函数中没有任何优势,因此我最终用Python编写了相同的代码(使用
请求
模块)。现在一切正常。但我仍然有兴趣知道如何在这里使用节点脚本解决问题。

最后的工作代码如下。不过,我仍然需要了解
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();
}

请首先查看并阅读有关AWS lambda的信息。
回调
函数是将响应发送回not
res.send
或其他函数的函数。最后两行是AWS lambda工作的原因。我没有反对,但回答错误。是的。NAVIN是正确的。如果我删除最后两行,我会由于配置原因而导致执行失败错误:Lambda代理响应格式不正确。方法已完成,状态为:502。这意味着API网关认为Lambda没有以正确的格式(状态代码、正文、标题)返回响应。嘿@NAVIN,你说得对,但是正在
res中调用回调函数('end'…
block,在响应到达时执行。我是否遗漏了什么?因为@Vikram3891收到502错误,可能是响应从未来自web服务器,这就是问题所在。
res.on('end'..
res
函数仅存在于
https.request
中。它是
https
的回调函数,不适用于lambda处理程序。lambda处理程序有自己的两个输入字段,
事件
内容
,和
回调
,与普通
express
框架
req
res
next
。写入
res.on(“end”…
中的回调确实会执行,但它是无效的,因为在最后一行中写入的回调已经执行,并且API网关已经对给定的API做出响应。回调函数在
req.end()之后写入
会立即被调用,因此会使用空响应对象进行响应。我只是在想,是否可以让最后一行中的回调等待响应对象被填充。删除
req.write(postData)
req.end()
。我只是猜测,lambda中不需要这些。这不是正常的nodeJs服务器。这是
serverless
。我意识到
req.end()
可以删除,尽管它不能解决问题-这是一个冗余行。我需要
req.write(postData)
否则,我将无法发布有效负载。@NAVINAgree和您提到的流。我被迫在最后一行添加
回调…
的原因是由于一些奇怪的行为(到目前为止对我来说)从Lambda API GATEWAY duo。如果我删除这一行,他们会开始抱怨执行失败,原因是配置错误:Lambda代理响应格式错误。方法已完成,状态为:502。似乎他们不会等到
res.on(“结束”)…
已执行。但作为添加回调行的附带损害,lambda正在发送空响应对象,因为它尚未填充。您需要调查两件事:首先检查response.body的格式。它必须是一个对象,可能第三方api使用了一些无效类型,无法解析为Json对象。第二:ch选中lambda execution timeout参数。在您有机会接收来自第三方api的响应之前,可能函数发出了超时信号。此外,出于上述相同原因,请检查response.statusCode的格式。如果删除最后一行,则会出现错误。不会出现错误