typescript - چرا این ویژگی JSON به صورت undefined ثبت میشود؟


من یک تابع لامبدا نودجیاس دارم که یک صف SQS به عنوان رویداد دارد، که به یک موضوع SNS مشترک شده است.

لامبدا به این صورت است:

'use strict';

import { Handler } from 'aws-lambda';

const myLambda: Handler = async (event: any = {}) => {
  let incomingMessage = JSON.stringify(event.Records[0].body);
  console.log('Received event:', incomingMessage); # log1
  console.log('parsed event',JSON.parse(incomingMessage)); # log2
  var type = JSON.parse(JSON.stringify(incomingMessage)).Type;
  console.log('Message received from SNS:', type); # log3
  return { };
};

export { myLambda }

من سه خط گزارش را حاشیهنویسی کردهام زیرا این کار بحث کردن در مورد آنها را کمی آسانتر میکند.

log1: این متن خام رویداد را نشان میدهد. log2: این پیام را به صورت قالببندیشده JSON زیبا (مرسی cloudwatch) نمایش میدهد:

{
    "Type": "Notification",
    "MessageId": "9245d801-2fe5-58ed-b667-8d9b73b2ff85",
    "TopicArn": "arn:aws:sns:eu-west-1:0123456:TopicName",
    "Subject": "Amazon SES Email Receipt Notification",
    "Message": "{json goes here}",
    "Timestamp": "2019-07-06T08:21:43.474Z",
    "SignatureVersion": "1",
    "Signature": "Signature goes here",
    "SigningCertURL": "https://sns.eu-west-1.amazonaws.com/SimpleNotificationService-1234567.pem",
    "UnsubscribeURL": "https://url.goes.here"
}

log3: این فقط undefined را لاگ میکند

من نمیفهمم چرا به صورت undefined نشان داده میشود و نه Notification.

این من هستم که در حال یادگیری لمبداهای تایپاسکریپت/نود هستم، پس ملایم باشید.

پاسخ شماره ۱

ماندن در جهت درست مفهومی نسبت به کپسولهسازی JSON در اینجا میتواند کمی پیچیده شود، زیرا چندین سرویس در یک زنجیره با هم تعامل دارند.

وقتی سرویسهای AWS با توابعی که با استفاده از محیط اجرایی Node.js Lambda مستقر شدهاند برای ارائه رویدادها تعامل دارند، در واقع تمام بار فراخوانی را به صورت یک شیء JSON روی ارتباط ارائه میدهند. این لایه JSON در واقع برای شما مورد علاقه نیست، زیرا Lambda بهطور شفاف این را به یک شیء JavaScript مناسب تجزیه میکند و آن را به شما به عنوان event تحویل میدهد.

وقتی یکپارچهسازی SQS/Lambda در حال جمعآوری رویدادها است، یک ساختار رویداد وجود دارد که شامل یک آرایه خارجی Records در شیء event است، و هر عضو آرایه شامل ویژگیهای یک پیام SQS منفرد است، همانطور که از عمل API ReceiveMessages SQS دریافت میشود. در این لایه نیز سریالسازی JSON وجود دارد، اما بار دیگر، این بهطور شفاف مدیریت میشود و آنچه انجام شده، خنثی میشود، بنابراین موضوعی برای علاقهمندی نیست.

یکپارچهسازی SQS در Lambda در واقع به شما گروهی از سرورهای مدیریت شده و مخفی را ارائه میدهد که صف SQS را بررسی میکنند تا این پیامها را جمعآوری کرده و آنها را به عنوان فراخوانیهای تابع به Lambda ارسال کنند.

در میان ویژگیها در هر شیء داخل آرایه Records، body وجود دارد که شامل رشتهای با محتوای پیام SQS است.

اگر شما در حال دریافت یک پیام SQS بودید که خودتان منتشر کرده بودید، این body دقیقاً شامل بایتهای بدنه پیام ارسال شده به SQS با فراخوانی SendMessage خواهد بود. این شفاف خواهد بود. هر چیزی که وارد کنید همان چیزی است که دریافت میکنید، چه متن ساده باشد، چه Base-64 یا JSON یا XML و غیره.

با این حال... شما یک صف SQS دارید که به یک موضوع SNS اشتراک دارد.

وقتی SNS را به SQS متصل میکنید:

پیام Amazon SQS شامل موضوع و پیامی است که به موضوع منتشر شده است همراه با متادادههای مربوط به پیام در یک سند JSON.

https://docs.aws.amazon.com/sns/latest/dg/sns-sqs-as-subscriber.html

«پیام Amazon SQS» که در بالا ذکر شد به معنای بدنه پیام است -- و این همان چیزی است که در ویژگی body پیدا میکنید، برای مثال event.Records[0].body.

«سند JSON» در body در واقع توسط SNS ایجاد شده است.

هنگامی که SNS پیامی را به SQS ارسال میکند، لایهای از محصورسازی JSON به خروجی خود اضافه میکند تا سایر خصوصیات پیام حفظ شوند، نه فقط بدنه پیام (که SNS آن را Message مینامد).

بنابراین چیزی که شما اینجا دریافت میکنید، body است که توسط SNS به SQS داده شده است، که SNS آن را به فرمت JSON کدگذاری کرده است. تمام کاری که باید انجام دهید این است که آن را با استفاده از JSON.parse() به یک شیء جاوااسکریپت تبدیل کنید.

let incomingMessage = JSON.parse(event.Records[0].body); 
let type = incomingMessage.Type;
console.log(type); // 'Notification'

شما همچنین احتمالاً خواهید دید که محتوای واقعی پیام SNS (پیامی که SNS از SES دریافت کرده است) نیز یک شیء JSON است. بنابراین:

let message = JSON.parse(incomingMessage.Message);

توجه کنید که ما در اینجا body را به یک شیء تبدیل میکنیم، صفت Message را از شیء بهدستآمده میگیریم -- که یک رشته حاوی یک شیء JSON است -- و آن را به یک شیء دیگر تبدیل میکنیم. از ابتدا، کاری که در خط بالا برای رمزگشایی آن پیام درونی انجام میدهیم، معادل این است -- اینجا برای توضیح اصل آورده شده است:

let message = JSON.parse(JSON.parse(event.Records[0].body).Message);

این ممکن است در ابتدا به نظر شما بسیار پیچیده و پیچیده باشد، اما دلایل خوبی وجود دارد که چرا این امر ضروری است. JSON از تودرتوی کامل سایر JSON ها و رفت و برگشت های تمیز، بدون گیج شدن مرزهای اشیا پشتیبانی می کند. SNS و SQS هر دو از ارائه تنها متن -- داده های کاراکتر -- به عنوان بار خود پشتیبانی می کنند ... بنابراین SES یک نمایش JSON از آنچه می خواهد به شما بگوید ایجاد می کند و آن را به SNS می فرستد ... سپس SNS یک نمایش JSON از آنچه باید به شما بگوید ایجاد می کند و آن را به SQS می فرستد ... بنابراین دو لایه از سریال سازی JSON وجود دارد که در نهایت باید SDA > Sdas > Sdas را پردازش کنید > SDAS برای لغو انجام دهید. اطلاعیه ها

به عنوان یادآوری:

JSON.stringify() یک شیء، آرایه، رشته، عدد، مقدار بولی یا null در جاوااسکریپت را دریافت میکند و آن را به رشتهای که حاوی JSON است سریالایز میکند. نوع بازگشتی آن رشته است. این عملیات همان عملیات «رمزگذاری» یا «سریالایز کردن» یا «تبدیل به JSON» است.

JSON.parse() یک شی JSON میخواهد -- یعنی یک متغیر رشتهای حاوی JSON، و آن را به یک شیء جاوااسکریپت، آرایه، رشته، عدد، بولین، یا null تبدیل میکند. نوع بازگشتی آن بستگی به این دارد که چه چیزی در لایه بیرونی رشته JSON سریالیشده باشد. این عملیات همان عملیات «رمزگشایی» یا «غیرفشردهسازی» یا «تبدیل از JSON» است. اگر هر رشتهای در داخل شیء JSON شامل JSON باشد، رمزگشایی بازگشتی نیست. آنها به عنوان رشته رمزگشایی میشوند و نه اشیاء درونشان، بنابراین اگر بخواهید به شئ درون آن به عنوان یک شیء جاوااسکریپت دسترسی پیدا کنید، نیاز به یک لایه اضافی JSON.parse() روی آن رشتههای حاصل دارید.