【发布时间】:2014-04-01 03:12:46
【问题描述】:
我一直在网上搜索,没有一个明确的答案可以确认来自亚马逊 SNS 的订阅请求。我已经将订阅从亚马逊控制台发送到我的网站,但下一步是什么?我使用 amazon EC2 作为我的 PHP 服务器。
【问题讨论】:
标签: amazon-web-services amazon-sns
我一直在网上搜索,没有一个明确的答案可以确认来自亚马逊 SNS 的订阅请求。我已经将订阅从亚马逊控制台发送到我的网站,但下一步是什么?我使用 amazon EC2 作为我的 PHP 服务器。
【问题讨论】:
标签: amazon-web-services amazon-sns
在通过 AWS 管理控制台配置 HTTP/HTTPS 终端节点订阅之前,您需要确保 PHP 网站的 HTTP 或 HTTPS 终端节点能够处理 Amazon SNS 生成的 HTTP POST 请求。 SNS 消息有多种类型:SubscriptionConfirmation、Notification 和 UnsubscribeConfirmation。您的 PHP 代码需要从请求中获取标头 x-amz-sns-message-type 并根据消息类型对其进行处理。对于 SubscriptionConfirmation 消息,您的 PHP 应用程序需要处理 POST 消息体,它是一个 JSON 文档。为了订阅主题,您的 PHP 代码需要访问 JSON 正文中指定的“SubscriberURL”。或者,您应该在订阅主题之前验证签名以确保消息的真实性。
您可以在 AWS 文档中找到更多详细信息:http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html
【讨论】:
这是一个确认 SNS 订阅的快速应用程序 (Node.js):
const express = require('express')
const request = require('request')
// parse urlencoded request bodies into req.body
const bodyParser = require('body-parser')
const app = express()
const port = 8080
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.post('/', (req, res) => {
let body = ''
req.on('data', (chunk) => {
body += chunk.toString()
})
req.on('end', () => {
let payload = JSON.parse(body)
if (payload.Type === 'SubscriptionConfirmation') {
const promise = new Promise((resolve, reject) => {
const url = payload.SubscribeURL
request(url, (error, response) => {
if (!error && response.statusCode == 200) {
console.log('Yess! We have accepted the confirmation from AWS')
return resolve()
} else {
return reject()
}
})
})
promise.then(() => {
res.end("ok")
})
}
})
})
app.listen(port, () => console.log('Example app listening on port ' + port + '!'))
要使用它,需要安装所需的软件包:
yarn add express request body-parser
一旦您确认订阅,AWS 将向服务器发送POST 请求,其中包含以下内容:
{
"Type": "SubscriptionConfirmation",
"MessageId": "XXXXXXXX-1ee3-4de3-9c69-XXXXXXXXXXXX",
"Token": "SECRET_TOKEN",
"TopicArn": "arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test",
"Message": "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test. To confirm the subscription, visit the SubscribeURL included in this message.",
"SubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test&Token=SECRET_TOKEN",
"Timestamp": "2018-11-21T19:48:08.170Z",
"SignatureVersion": "1",
"Signature": "SECRET",
"SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem"
}
有效载荷包含服务器请求的SubscribeURL。
【讨论】:
您指定的端点将从 AWS SNS 端点验证服务获取数据,相同的端点将用于验证端点并从 aws 获取通知,
只需将 AWS SNS 发送的输入转储到一个文本文件中,例如,
$json_write_to_text = json_decode(file_get_contents("php://input"));
您将找到 AWS SNS 发送的所有数据,但只需找到 SubscriptionUrl(特定于具有有效令牌的端点),在浏览器中打开它,您将获得 SubscriptionConfirmation 状态。就是这样
享受吧。
【讨论】:
$body = json_decode($request->getContent(),true) 可以使用。
带有注解的Spring云SNS订阅
spring cloud AWS已经支持订阅者自动确认,你只需要把这个注解“@NotificationSubscriptionMapping”
@Controller
@RequestMapping("/topicName")
public class NotificationTestController {
@NotificationSubscriptionMapping
public void handleSubscriptionMessage(NotificationStatus status) throws IOException {
//We subscribe to start receive the message
status.confirmSubscription();
}
@NotificationMessageMapping
public void handleNotificationMessage(@NotificationSubject String subject, @NotificationMessage String message) {
// ...
}
@NotificationUnsubscribeConfirmationMapping
public void handleUnsubscribeMessage(NotificationStatus status) {
//e.g. the client has been unsubscribed and we want to "re-subscribe"
status.confirmSubscription();
}
}
http://cloud.spring.io/spring-cloud-aws/spring-cloud-aws.html#_sns_support
【讨论】:
我使用 NodeJS 后端解决了这个问题。假设您在 HapiJS 中有这样的 API(好吧,您可以拥有其他技术也没关系)
{
method: 'POST',
path: '/hello',
handler: ( request, reply ) => {
reply( Hello.print(request.payload) );
},
config: {
tags: ['api']
}
}
只需将您收到的有效负载传递给您的业务逻辑。
在业务逻辑过程中是这样的
'use strict';
const request = require('request');
exports.print = (payload) => {
payload = JSON.parse(payload);
if(payload.Type === 'SubscriptionConfirmation'){
return new Promise((resolve, reject) => {
const url = payload.SubscribeURL;
request(url, (error, response) => {
if (!error && response.statusCode == 200) {
console.log('Yess! We have accepted the confirmation from AWS');
return resolve();
}
else
return reject();
});
});
}
我正在使用 NPM 的请求模块来自动接受此类请求。
另一种方法是打印payload 的内容,然后单击payload.SubscribeURL 中给出的URL。
一旦 AWS 接受它,您在订阅页面上检查确认,其中 Subscription ARN 将从 Pending Confirmation 更改为具有您的主题名称的复杂名称兼 SHA。
【讨论】: