Twilio API 调用适用于本地环境,但不适用于 AWS Lambda 函数

Posted

技术标签:

【中文标题】Twilio API 调用适用于本地环境,但不适用于 AWS Lambda 函数【英文标题】:Twilio API call works from local environment but not AWS Lambda function 【发布时间】:2022-01-17 08:50:03 【问题描述】:

问题

我想从 Lambda 函数(node.js v12 运行时)运行以下代码:

const client = require('twilio')(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);

console.log("Start.");
client.messages.create(
  body: 'Msg',
  to: '+1234567890',// a verified number
  from: '+1234567890' // a valid Twilio number
)
.then((message) => 
  console.log(message.sid);
)
.catch((e) => 
  console.log(Error(e));
  console.log("Error in Signup");
);

console.log("Done.");

我可以在本地运行它,并且我应该将消息接收到目标号码,但是当我把它全部压缩,将它移动到 Lambda 并运行它时,我只得到 StartDone,没有create 函数的输出和没有短信。

尝试的解决方案

我已尝试将环境变量替换为实际值,以确保那里不存在问题,我检查了 Twilio 日志,除了我在本地进行的成功调用之外,没有其他任何内容。

我可以确认,每次运行时,它都会到达client.messages.create,然后似乎只是跳过它,没有输出,接下来是Done

我让它工作了一次,通过在第一行之前添加 console.log(process.env.ACCOUNT_SID) 语句(这是在使用环境变量而不是硬编码值时),日志语句的输出是 undefined 但对于无论发送消息的原因是什么,它都会输出消息的 SID。然后它又停止工作了。

几个小时后,当我在创建client 后添加console.log(client.messages) 时,同样的事情发生了。之后它再次停止工作。

任何帮助都将不胜感激,我从来没有像现在这样相信恶作剧者。

完整代码

大部分内容来自here 和here。

exports.handler = async (event, context, callback) => 
    const AWS = require('aws-sdk');
    const b64 = require('base64-js');
    const encryptionSdk = require('@aws-crypto/client-node');
    const Twilio = require('twilio');
            
    // Configure the encryption SDK client with the KMS key from the environment variables.  
            
    const  encrypt, decrypt  = encryptionSdk.buildClient(encryptionSdk.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT);
    const generatorKeyId = process.env.KEY_ALIAS;
    console.log(process.env.KEY_ALIAS);
    const keyIds = [ process.env.KEY_ID ];
    console.log(process.env.KEY_ID);
    const keyring = new encryptionSdk.KmsKeyringNode( generatorKeyId, keyIds );
    
    // Decrypt the secret code using encryption SDK.
          
    let plainTextCode;
    if(event.request.code)
        const  plaintext, messageHeader  = await decrypt(keyring, b64.toByteArray(event.request.code));
        plainTextCode = plaintext;
    

    // Your Account SID from www.twilio.com/console
    // See http://twil.io/secure for important security information
    const accountSid = process.env.ACCOUNT_SID;
    console.log(process.env.ACCOUNT_SID);

    // Your Auth Token from www.twilio.com/console 
    // See http://twil.io/secure for important security information
    const authToken = process.env.AUTH_TOKEN;
    console.log(authToken);
            
    if(event.triggerSource == 'CustomSMSSender_SignUp')
        console.log('CustomSMSSender_SignUp');
        // Send sms to end-user using custom or 3rd party provider.
        // Import Twilio's Node Helper library
        // Create an authenticated Twilio Client instance
        const client = require('twilio')(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);
        // Send a text message
        client.messages.create(
            body: `You're verification code is $plainTextCode.toString().`,
            to: event.request.userAttributes.phone_number,  // user's phone number
            from: '+1234567890' // redacted, actual value is a Twilio phone number
        )
            .then((message) => 
                // Success, return message SID
                console.log(message.sid);
            )
            .catch((e) => 
                // Error, return error object
                console.log(Error(e));
                console.log("Error in Signup");
            );
            
    
;


当我在这里时,如果有人能解释为什么我可以打印 KEY_ALIAS 和 KEY_ID 环境变量,但 ACCOUNT_SID 和 AUTH_TOKEN 都被记录为 undefined,则可以加分。它们都存在。

【问题讨论】:

您是否尝试在thencatch 块中添加callback()? Twilio messages.create 异步运行,因此您的函数可能在发送消息之前完成。这是我基于片状行为的最佳猜测。 【参考方案1】:

这里是 Twilio 开发者宣传员。

您正在使用标记为 async 的 Lambda 函数,只要在函数内完成所有处理(包括异步处理),只要它使用 await 关键字,该函数就会立即返回。问题是您调用了 Twilio API,这是一个异步函数,但不使用 await,因此处理立即完成,Lambda 函数结束。

AWS 实际上会暂停 JS 事件循环并在再次调用 Lambda 时恢复它,因此您甚至可能会发现在运行函数 like this questioner did 后几秒或几分钟内传递的消息。

解决方法是await调用API的结果。然后,您可以将其包装在 try/catch 中以从错误中恢复,而不是使用 .then.catch

exports.handler = async (event, context, callback) => 
  const b64 = require("base64-js");
  const encryptionSdk = require("@aws-crypto/client-node");
  const Twilio = require("twilio");

  // Configure the encryption SDK client with the KMS key from the environment variables.

  const  decrypt  = encryptionSdk.buildClient(
    encryptionSdk.CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT
  );
  const generatorKeyId = process.env.KEY_ALIAS;
  console.log(process.env.KEY_ALIAS);
  const keyIds = [process.env.KEY_ID];
  console.log(process.env.KEY_ID);
  const keyring = new encryptionSdk.KmsKeyringNode( generatorKeyId, keyIds );

  // Decrypt the secret code using encryption SDK.

  let plainTextCode;
  if (event.request.code) 
    const  plaintext  = await decrypt(
      keyring,
      b64.toByteArray(event.request.code)
    );
    plainTextCode = plaintext;
  

  if (event.triggerSource == "CustomSMSSender_SignUp") 
    console.log("CustomSMSSender_SignUp");

    // Create an authenticated Twilio Client instance
    const client = Twilio(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);
    try 
      // Send a text message
      const message = await client.messages.create(
        body: `You're verification code is $plainTextCode.toString().`,
        to: event.request.userAttributes.phone_number, // user's phone number
        from: "+1234567890", // redacted, actual value is a Twilio phone number
      );
      // Success, return message SID
      console.log(message.sid);
     catch (error) 
      // Error, return error object
      console.log(Error(e));
      console.log("Error in Signup");
    
  
;

至于process.env.ACCOUNT_SIDprocess.env.AUTH_TOKEN 被注销为undefined,这表明它们没有正确设置。确保他们是configured in the correct environment。

【讨论】:

谢谢!这已经解决了!尽管如此,环境变量仍然很奇怪。它们都是通过控制台设置在一起的,我可以登录的两个使用了我不能登录的两个使用的所有字符,很奇怪。但据我所知,没有影响。 :) 很奇怪,但只要它不工作!

以上是关于Twilio API 调用适用于本地环境,但不适用于 AWS Lambda 函数的主要内容,如果未能解决你的问题,请参考以下文章

对 On Premise Exchange 的 Graph API 调用仅适用于 Playground

GroupBy 转换运算符仅适用于本地环境

使用 CORS 与 LocomotiveJs 一起休息 API。适用于本地机器,但不适用于 Amazon 或 Heroku

Paypal REST api 调用适用于 cURL,但不适用于 C# 代码

地理位置仅适用于本地主机

部分视图部分适用于 JQuery,但不完全适用于 C# ASP.Net MVC 5