【问题标题】:Sending compressed text over Amazon SQS from PHP to NodeJS通过 Amazon SQS 从 PHP 向 NodeJS 发送压缩文本
【发布时间】:2016-03-07 12:58:17
【问题描述】:

我似乎无法通过 Amazon SQS 将压缩消息从 PHP 发送到 NodeJS。

在 PHP 方面我有:

$SQS->sendMessage(Array(
    'QueueUrl'    => $queueUrl,
    'MessageBody' => 'article',
    'MessageAttributes' => Array(
        'json' => Array(
            'BinaryValue' => bzcompress(json_encode(Array('type'=>'article','data'=>$vijest))),
            'DataType' => 'Binary'
        )
    )
));

注意 1:我也尝试将压缩数据直接放入消息中,但库给了我一个错误,其中包含一些无效的字节数据

在节点方面,我有:

body = decodeBzip(message.MessageAttributes.json.BinaryValue);

消息来自 sqs.receiveMessage() 调用,并且该部分有效,因为它适用于原始(未压缩的消息)

我得到的是TypeError:格式不正确

我也尝试过使用:

PHP - 节点

gzcompress() - zlib.inflateraw()

gzdeflate() - zlib.inflate()

gzencode() - zlib.gunzip()

每一对都给了我相同错误的版本(本质上,输入数据是错误的)

鉴于我开始怀疑消息传输中的某个错误

我做错了什么?

编辑 1:似乎错误在传输中,因为 php 中的 bin2hex() 和 Node 中的 .toString('hex') 返回完全不同的值。似乎 PHP 中的 Amazon SQS API 使用 base64 传输 BinaryAttribute,但 Node 无法对其进行解码。我设法通过关闭亚马逊aws配置文件中的自动转换然后在节点中手动解码base64来部分解码它,但它仍然无法解码它。

编辑 2:我设法通过在 php 端使用 base64_encode() 并将 base64 作为 messageBody(不使用 MessageAttributes)发送来完成同样的事情。在节点方面,我使用了 new Buffer(messageBody,'base64') 然后 decodeBzip 。一切正常,但我仍然想知道为什么 MessageAttribute 不能正常工作。当前的 base64 增加了开销,我喜欢按预期使用服务,而不是通过变通方法。

【问题讨论】:

  • SQS 基本上是为面向文本的消息而设计的——"Amazon SQS messages can contain up to 256KB of text data"——除非 JSON 编码过程总是巧合地产生有效的 UTF-8 输出,否则我可以理解为什么会有问题。 . base64 编码负载当然会取消压缩的一些好处,因为编码 base-64 会导致 3:4 字节扩展......但仍应导致负载大小的净减少。试试看?
  • 是的,但是 SQS 确实有 BinaryAttribute 应该完全用于此目的?他们甚至在他们的文档中说 BinaryAttribute 可用于传输图像、压缩数据等。
  • 哦,我明白你在做什么了。公平的问题。我再看看。
  • 我会检查从 SQS 收到的原始消息,将在 message.MessageAttributes.json.BinaryValue 中找到的字节与您最初写入的字节进行比较。如果您检查双方的十六进制转储,应该很容易确定它是否被损坏或更改。
  • 我希望bzcompress() 的输出以42 5a 68 开头,即bzip2 幻数的前三个字节。

标签: php node.js zlib amazon-sqs


【解决方案1】:

This 是所有 SQS 库在后台所做的。可以获取SQS库的php源码,自己看看。二进制数据将始终进行 base64 编码(无论是否使用 MessageAttributes,都无关紧要),以满足 API 对具有 form-url-encoded 消息的要求。

我不知道你的 $vijest 中的数据有多长,但我敢打赌,经过压缩和 base64 编码后,它会比以前更大。

所以我给你的答案是两部分(如果你真的很固执,再加上第三部分):

  • 查看底层原始 API 时,绝对清楚不使用 MessageAttributes 不会增加 base64 的额外开销。相反,由于 SQS php 库强制执行的数据结构,使用 MessageAttributes 会增加一些额外的开销。因此,不使用 MessageAttributes 显然不是一种解决方法,如果您想自己压缩数据并让它以这种方式工作,您应该这样做。
  • 由于 http POST 请求的性质,在应用程序中压缩数据是一个非常糟糕的主意。 Base64 开销可能会抵消压缩优势,您最好发送纯文本。
  • 如果您绝对不相信我或 API 规范或 HTTP 规范并想继续,那么我建议在 BinaryValue 参数中发送一个简单的短字符串“teststring”,并将您发送的内容与您收到的内容进行比较。这将很容易理解 SQS 库对 BinaryValue 参数所做的转换。

【讨论】:

  • 谢谢!你证实了我今天早些时候意识到的。我不确定为什么我认为像这样使用它会增加开销,最终它都是 url,所以更短的消息对象,更短的 url。我的消息平均约为 10k,而 gzip 将其减少到约 3k。因此,4:3 的比率约为 4。将其乘以每小时约 2.000 条消息,确实会产生影响。感谢您的洞察力!
  • 有一件事仍然困扰着我。如果 PHP 端进行 base64 编码,Node 进行解码,为什么在 Node 端会失败?不应该是透明的吗?
  • 但是您应该检查 curl 或任何 php 用于发送消息的内容,并且亚马逊网络服务器无论如何都不会压缩消息。我看起来不是很彻底,但我至少发现了一些证据表明通信无论如何都被压缩了。启动 wireshark 并在消息中查找 content-encoding:gzip。
  • 对于你的另一个问题,你可以使用我的第三部分来分析。我的猜测是他们并没有真正使用 php 客户端测试他们的节点服务器并且出了点问题。您可以针对 php 服务器测试您的 php 客户端吗?另外,我可以礼貌地要求赏金吗? :)
  • 尽管您的回答并未阐明“为什么”会发生这种情况,但它帮助我意识到使用 base64 作为消息文本时实际上没有开销(相反,它甚至可能使用更少的数据转移),所以是的,你可以得到赏金 :) 再次感谢
【解决方案2】:

gzcompress() 将被zlib.Inflate() 解码。 gzdeflate() 将被 zlib.InflateRaw() 解码。 gzencode() 将被 zlib.Gunzip() 解码。所以在你列出的三个中,有两个是错误的,但一个应该可以。

【讨论】:

  • 嘿,马克,我想到了这一点,所以我尝试了所有可能的组合(甚至为 Node 使用了一些 3rd 方模块),但仍然失败。如果您检查我的问题(编辑 1),错误似乎在传输中,因为在 Node 中我收到的内容与我在 PHP 中发送的内容完全不同。
猜你喜欢
  • 2010-12-12
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多