为什么将此JSON属性记录为未定义? [英] Why is this JSON property being logged as undefined?

查看:70
本文介绍了为什么将此JSON属性记录为未定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个nodejs lambda,它具有一个SQS队列作为事件,并已订阅了SNS主题.

I have a nodejs lambda that has an SQS queue as an event, which is subscribed to an SNS topic.

lambda看起来像这样:

The lambda looks like this:

'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 }

我已经注释了三行日志,因为这样会使讨论变得容易一些.

I've annotated the three log lines because it'll make it a bit easier to talk about.

日志1::显示事件的裸文本. log2:这显示了消息的JSON格式(谢谢cloudwatch):

log1: This shows the bare text of the event. log2: This shows a nice JSON formatted (thank you cloudwatch) of the message:

{
    "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.

I don't understand why it's showing as undefined and not Notification.

这是我在学习打字稿/节点lambda的内容,所以要保持柔和.

This is me learning typescript/node lambdas so be gentle.

推荐答案

在这里,关于JSON封装保持正确的概念定位可能会有些棘手,因为多个服务正在级联中进行交互.

Remaining correctly conceptually oriented with regard to the JSON encapsulation here can get a little tricky, because multiple services are interacting in a cascade.

当AWS服务与使用Node.js Lambda运行时部署的功能进行交互以提供事件时,它们实际上将整个调用有效负载作为JSON对象提供给网络. JSON实际上对您并不感兴趣,因为Lambda透明地将其解析为正确的JavaScript对象,并将其作为event交给您.

When AWS services interact with functions deployed using the Node.js Lambda runtimes to supply events, they actually supply the entire invocation payload as a JSON object on the wire. This layer of JSON isn't actually of interest to you, because Lambda transparently parses this into a proper JavaScript object and hands it to you as event.

当SQS/Lambda集成正在汇总事件时,会出现一个

When the SQS/Lambda integration is aggregating events, there is an event structure with an outer Records array in the event object, and each member of the array contains the properties of a single SQS message, as received from the SQS ReceiveMessages API action. There is JSON serialization at this layer as well, but once again, it is transparently handled and what's done gets undone, so it is of no interest.

(Lambda的SQS集成实际上为您提供了一组隐藏的托管服务器,这些服务器轮询SQS队列以收集这些消息并将它们作为函数调用提交给Lambda.)

(Lambda's SQS integration actually provides you with a group of hidden, managed servers that poll the SQS queue to collect these messages and submit them to Lambda as function invocations.)

Records数组中每个对象的属性中是body,其中包含带有SQS消息有效负载的字符串.

Among the properties in each object inside the Records array is body, which contains a string with the payload from the SQS message.

如果您自己捕获自己发布的SQS消息,则此body将完全包含通过

If you were capturing an SQS message you had published, yourself, this body would contain exactly the message body bytes sent to SQS with the SendMessage call. It would be transparent. Whatever you put in is what you'd get out, whether it was plain text or Base-64 or JSON or XML, etc.

但是...您有一个已订阅SNS主题的SQS队列.

However... you have an SQS queue that is subscribed to an SNS topic.

将SNS连接到SQS时:

When you connect SNS to SQS:

Amazon SQS消息包含发布到主题的主题和消息,以及有关JSON文档中消息的元数据.

The Amazon SQS message contains the subject and message that were published to the topic along with metadata about the message in a JSON document.

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

上面提到的"Amazon SQS消息"表示消息正文,这就是您在body属性中找到的内容,例如event.Records[0].body.

"The Amazon SQS message" referred to above means the message body -- and this is what you find in the body property, e.g. event.Records[0].body.

body中的"JSON文档"实际上是由SNS创建的.

The "JSON document" in the body is actually created by SNS.

当SNS将消息传递到SQS时,它会在其自己的输出中添加一层JSON封装,以便保留消息的其他属性,而不仅保留正文有效负载(SNS称为Message).

When SNS delivers a message to SQS, it adds a layer of JSON encapsulation to its own output, so that the other properties of the message are preserved, not just the body payload (which SNS calls Message).

因此,您在这里收到的是SNS提供给SQS的body,SNS已将其编码为JSON.您需要做的就是使用JSON.parse()将其解析为JavaScript对象.

Thus what you are receiving here is the body supplied to SQS by SNS, which SNS has encoded in JSON. All you need to do is parse that into a JavaScript object using JSON.parse().

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

您还可能会发现实际SNS消息(从SES接收到的消息SNS)的有效载荷也是JSON对象.就是这种情况:

You are also likely to find that the payload of the actual SNS message (the message SNS received from SES) is a JSON object as well. That being the case:

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

请注意,我们正在将body解析为一个对象,并从结果对象中获取Message属性(该属性是一个包含JSON对象的字符串),然后将其解析为另一个对象.从顶部开始,我们在上一行中所做的用于解码最内层消息的操作与此等效—在这里显示该原理:

Note here that we're parsing body into an object, taking the Message attribute from the resulting object -- which is a string containing a JSON object -- and parsing that into another object. From the top, what we're doing, in the line above, to decode that innermost message is equivalent to this -- shown here for illustration of the principle:

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

这最初可能会让您感到非常复杂和令人费解,但是有充分的理由说明为什么有必要这样做. JSON支持其他JSON的完美嵌套和干净的往返,而不会混淆对象边界. SNS和SQS都仅支持传递文本(字符数据)作为有效载荷……因此 SES为要告诉您的内容创建一个JSON表示形式,然后将其发送给SNS ...然后,SNS为需要告诉您的内容创建一个JSON表示形式并将其发送给SQS. ..因此,为了处理SES> SNS> SQS> Lambda事件通知,最终需要撤销两层JSON序列化.

This may initially strike you as quite complex and convoluted, but there are good reasons why this is necessary. JSON supports perfect nesting of other JSON and clean round trips, without confusing object boundaries. SNS and SQS both support delivering only text -- character data -- as their payload... so SES creates a JSON representation of what it wants to tell you and sends it to SNS... then SNS creates a JSON representation of what it needs to tell you and sends it to SQS... so there are two layers of JSON serialization that you will ultimately need to undo, in order to process SES > SNS > SQS > Lambda event notifications.

提醒一下:

JSON.stringify()需要JavaScript对象,数组,字符串,数字,布尔值或null,并将其序列化为包含JSON的字符串.它的返回类型是字符串.这是编码"或序列化"或至JSON"操作.

JSON.stringify() expects a JavaScript object, array, string, number, boolean, or null and serializes it into a string containing JSON. Its return type is string. This is the "encode" or "serialize" or "to JSON" operation.

JSON.parse()需要一个JSON对象-即包含JSON的字符串变量,并将其转换回JavaScript对象,数组,字符串,数字,布尔值或null.它的返回类型取决于最外层序列化到JSON字符串中的内容.这是解码"或反序列化"或来自JSON"操作.如果JSON对象中的任何字符串包含JSON,则解码不是递归的.它们被解码为字符串,而不是字符串中的对象,因此,如果要以JavaScript对象的形式访问其中的对象,则需要对这些结果字符串加上JSON.parse()的附加层.

JSON.parse() expects a JSON object -- that is, a string variable containing JSON, and converts it back to a JavaScript object, array, string, number, boolean, or null. Its return type depends on what's been serialized into the JSON string at the outermost layer. This is the "decode" or "deserialize" or "from JSON" operation. If any strings within the JSON object contain JSON, the decoding is not recursive. They are decoded as strings, and not the objects within, so an addition layer of JSON.parse() against those resulting strings is needed if you want to access the object within as a JavaScript object.

这篇关于为什么将此JSON属性记录为未定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆