使用 AWS SNS 发送通知到 HTTP 终端

该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2016/08/27/use-aws-sns-with-a-http-endpoint/

Overview

AWS 的 SNS 是一个消息推送服务,通过 SNS,可以将 AWS 的其他服务(如 S3)的事件消息转发给 其它终端(E-Mail,HTTP服务器等)。

其它终端(E-Mail,HTTP服务器等)。

一般情况下 SNS 的消息是一次性的,发完就消失了,当然也可以配置延迟发送的消息,这里只讲第一种。

下面直接开始说使用方式。

1. 创建 SNS 主题

主题是指一个消息集合,一个主题可储存多条消息,其他 AWS 服务可以将某些消息发到这个 SNS 主题下。

订阅是指:谁订阅了这个主题,主题就将其中的消息分发给这些订阅者,例如 HTTP 终端。

在使用之前必须先至少创建一个 SNS 主题,主题名称为 test,显示名随意。

2. 创建一个订阅(HTTP为例)

创建号了 SNS 主题后,下面有一个很大的按钮,叫你创建订阅,但是,先不要理他!

因为你一旦创建了一个订阅,AWS 马上就会发一个确认请求到那个地址——明显你应该还没准备好。

下面我们先说说怎么确认。 »> 官方教程 «<

不过官方教程有点长,我这里直接说最简单的方法。

AWS SNS 做这个确认订阅操作,就像我们注册网站账户的时候要验证邮箱或者手机一样,确认这个 HTTP 终端是你在用,否则你随便添加一个 HTTP 地址,天天叫 AWS 发请求,岂不是麻烦大了。

这就是确认订阅的目的。

当然了,确认订阅也和我们注册账户很像,它发送一个 HTTP POST 请求到你的地址,比如我这是 http://fenying.net/aws/sns/test/,当然了,这个地址是骗你们的。

它发送的 HTTP Body 是一个 JSON 结构,其中字段 SubscribeURL 里面是确认地址,用 HTTP GET 调用这个地址就可以完成订阅确认,这里用 PHP 代码处理:

 1<?php
 2/**
 3 * /aws/sns/test/index.php
 4 */
 5$rawData = file_get_contents('php://input');
 6$_POST = json_decode($rawData);
 7
 8$ch = curl_init($_POST->SubscribeURL) ;
 9
10curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
11curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
12curl_exec($ch) ;
13curl_close($ch);

现在我们来创建一个 HTTP 类型的订阅,地址写你的处理地址,我这里是 http://fenying.net/aws/sns/test/

创建完成,AWS 会发送一个确认请求到上面的地址。

3. 绑定 S3 Bucket 和 SNS

首先给我们的 SNS 主题 test 添加策略,修改为所有人都可以发消息。

然后进入 S3 控制台,选择一个 Bucket 查看属性,在 Events 栏里面添加一个事件,我选择的是 PUT,然后选择我们的 test SNS 主题,随便写个前缀(这里用 upload/)和名称,然后保存。

有没有绑定成功现在还无法确认,因为我们没有修改代码。下面写个简单的 DEMO:

 1<?php
 2/**
 3 * /aws/sns/test/index.php
 4 */
 5file_put_contents(
 6    's3.sns.log', 
 7    $_SERVER['REQUEST_URI'] . PHP_EOL .
 8    json_encode($_SERVER, 1) . PHP_EOL .
 9    file_get_contents('php://input') . PHP_EOL . PHP_EOL,
10    FILE_APPEND
11);

设置完毕,下面开始测试吧,上传一个文件到刚才的储存桶下面,key 比如 upload/test.zip

然后去我们的服务器上查看下 s3.sns.log 文件,就可以得到具体的请求数据结构了。

4. 安全检测

我们的 HTTP 终端需要检测是否调用信息来自 AWS SNS,一个最简单的方法是根据 SNS Topic ARN 判断, 请求的 SNS Topic ARN 通过 $_SERVER['HTTP_X_AMZ_SNS_TOPIC_ARN'] 可以获取到,即 HTTP 请求头里面的字段 x-amz-sns-topic-arn

SNS Topic 的 ARN 可以在 SNS 控制台看到,一个典型的 SNS Topic ARN 是一个 arn:aws:sns:us-east-1:123456789012:sample

当然,还有更安全的方法是,使用亚马逊提供的哈希校验算法,根据 POST 的 JSON 里面的字段实现, 这个比较复杂,就不说明了,请查看官方文档。

(完)

comments powered by Disqus