简体   繁体   English

AWS Lambda Node.js 环境在第一次 API 调用时无法循环插入到 Mysql

[英]AWS Lambda Node.js Environment Failed to Loop Insert to Mysql on First API Call

I'm trying to create function in AWS Lambda (node.js), which call some REST API, dan insert the API result to MySQL DB.我正在尝试在 AWS Lambda (node.js) 中创建函数,它调用一些 REST API,并将 API 结果插入 MySQL DB。

While the requirement is very simple, but I encounter some problem when deploying to AWS Lambda (not happening on my local machine), where my first API call only resulting only 1 data is inserted, while the second API call forward, it insert all 4 data as intended.虽然要求非常简单,但我在部署到 AWS Lambda 时遇到了一些问题(在我的本地机器上没有发生),我的第一个 API 调用只导致插入了 1 个数据,而第二个 API 调用转发,它插入了所有 4数据如预期。 I try various solution available on stack overflow, and all resulting the same.我在堆栈溢出时尝试了各种可用的解决方案,结果都是一样的。

Another problem is that the result is always {"message": "Internal server error"}, even though the data is inserted correctly on second API call forwards另一个问题是结果总是 {"message": "Internal server error"},即使数据在第二个 API 调用转发时正确插入

Basically i don't have much experience with Node.js, so i would appreciate if anyone could help me.基本上我对 Node.js 没有太多经验,所以如果有人能帮助我,我将不胜感激。

 'use strict';

const connection = require('serverless-mysql')({
    config: {
      host: 'xxxxxx.xxxxx.ap-southeast-1.rds.amazonaws.com',
      user: 'xxx',
      password: 'xxx',
      database: 'xxx_db'
    }
})
const axios = require('axios');

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

  //Get Data From API
  axios.get('https://xxx.xyz/wp-json/wp/v2/posts')
  .then(res => {
    const headerDate = res.headers && res.headers.date ? res.headers.date : 'no response date';
    console.log('Status Code:', res.status);
    console.log('Date in Response header:', headerDate);

    //this should result 4 data
    const posts = res.data;
      
    posts.forEach(post => {
        var sql = `INSERT INTO tbl_post(news_id, title, excerpt, content, category, image_link, modified_date, show_in_banner_F, show_in_list_F) VALUES ('${post.id}', '${post.title.rendered}', '${post.excerpt.rendered}', '${post.content.rendered}', '', '${post.yoast_head_json.og_image[0].url}', now(), 0, 0)`;  
        console.log(sql);
        let insert_query = connection.query(sql);
    });

    console.log("finished");
    connection.end();
    
    let responseBody = { message: "OK" };
    let response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
        body: JSON.stringify(responseBody)
    };
    return response;

  })
  .catch(err => {
    console.log('Error: ', err.message);
    let responseBody = { message: "Fail" };
    let response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
        body: JSON.stringify(responseBody)
    };
    return response;
  });
}

First of all a forEach loop will call connection.query(sql) function multiple times then exit the loop without actually waiting for each query to finish executing so you'll end up executing random number of queries each time you run this loop instead what you want to do is use async/await await connection.query(sql) in order to wait for each query inside the loop to finish executing before exiting the loop.首先, forEach循环将多次调用connection.query(sql)函数,然后退出循环而不实际等待每个查询完成执行,因此每次运行此循环时您最终都会执行随机数量的查询,而不是您执行的操作想要做的是使用 async/await await connection.query(sql)以便在退出循环之前等待循环内的每个查询完成执行。

Also forEach loop is not designed for asynchronous code so you'll have to change that as well and use for...of instead.此外forEach循环不是为异步代码设计的,因此您也必须更改它并使用for...of代替。 And you also have to use prepared statements using ?而且您还必须使用准备好的语句使用? instead of inserting values with ${variable} to prevent sql injections.而不是用${variable}插入值来防止 sql 注入。

for (const post of posts) {
   const sql = "INSERT INTO tbl_post(news_id, title) VALUES (?, ?)";
   const values = [post.id, post.title.rendered];
   console.log(mysql.format(sql,values)); // This would log query after values substitution 
   await connection.execute(sql, values);
 }

So the final code will look something like this:所以最终的代码看起来像这样:

exports.handler = async (event, context) => {
  try {
    //Get Data From API
    const res = await axios.get("https://xxx.xyz/wp-json/wp/v2/posts");
    const headerDate = res.headers && res.headers.date ? res.headers.date : "no response date";
    console.log("Status Code:", res.status);
    console.log("Date in Response header:", headerDate);

    //this should result 4 data
    const posts = res.data;
    for (const post of posts) {
      const sql = "INSERT INTO tbl_post(news_id, title) VALUES (?, ?)";
      const values = [post.id, post.title.rendered];
      console.log(mysql.format(sql, values)); // This would log query after values substitution
      await connection.execute(sql, values); // Execute prepares statement first then executes it.
    }

    console.log("finished");
    await connection.end();

    let responseBody = { message: "OK" };
    let response = {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Headers": "Content-Type",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
      },
      body: JSON.stringify(responseBody),
    };
    return response;
  } catch (err) {
    console.log("Error: ", err.message);
    let responseBody = { message: "Fail" };
    let response = {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Headers": "Content-Type",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
      },
      body: JSON.stringify(responseBody),
    };
    return response;
  }
};

As a side note consider using transactions if u want to guarantee that all queries inside the loop either succeed or fail.作为旁注,如果您想保证循环内的所有查询成功或失败,请考虑使用事务。

Pro tip: use Promise.all() if u want to execute multiple async functions at the same time not one after the other.专业提示:如果您想同时执行多个异步函数,而不是一个接一个地执行,请使用Promise.all()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM