在AWS中使用http进行SNS主题订阅

时间:2018-08-22 02:21:49

标签: amazon-sns

我在SNS主题中创建了Http订阅。 SNS订阅中提到的网址是一个EC2实例。

需要知道在EC2实例中将从何处接收SNS订阅请求。

要订阅http请求,我必须在EC2中安装哪些应用程序。使用的端口是8080。

1 个答案:

答案 0 :(得分:0)

如基于SNS HTTP(S)的Amazon Doc订阅中所述...... more

在为主题订阅HTTP或HTTPS终端节点之前,必须确保HTTP或HTTPS终端节点可以处理Amazon SNS用于发送订阅确认和通知消息的HTTP POST请求。当您订阅HTTP终端节点时,Amazon SNS向其发送订阅确认请求。创建预订时,您的端点必须准备好接收和处理此请求,因为 Amazon SNS当时发送了此请求。在您确认订阅之前,Amazon SNS不会将通知发送到终端。确认订阅后,当对已订阅主题执行发布操作时,Amazon SNS将向终端发送通知。

在处理 SubscriptionConfirmation 请求之前,状态始终为待确认状态,并且不会收到任何 Notification 消息。


以下是自动处理 SubscriptionConfirmation Notification UnsubscribeConfirmation messageType请求以及 Content-Type 的代码段>对于由AWS SNS触发的上述请求,始终采用 文本/纯文本 格式。

春季启动方式

使用带有以下代码的SNS使用者使用Spring-boot的主要优点是,您无需依赖任何AWS指定配置及其依赖项。如果您的微服务是使用spring-boot而不是spring-cloud-aws-messaging构建的,则这是一种实用的方法。客户方应用程序中需要执行以下步骤。

将以下注释添加到请求处理程序方法中以进行处理 SubscriptionConfirmation UnsubscribeConfirmation messageType。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SNSSubscriptionUnSubscriptionConfirmation {
}

如果使用@SNSSubscriptionUnSubscriptionConfirmation,注释的请求处理程序方法将触发以下方面,则该方法将处理基于Http的 SubscriptionConfirmation UnsubscribeConfirmation messageTypes (s)请求标头x-amz-sns-message-type

@Aspect
@Component
@Slf4j
public class SNSSubscriptionUnSubscriptionActivation {

    @Before(value = "@annotation(SNSSubscriptionUnSubscriptionConfirmation)")
    public void SNSSubscriptionUnSubscriptionConfirmationActivation(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        HttpServletRequest httpServletRequest = (HttpServletRequest)args[0];
        String requestBody = (String)args[1];
        String messageType = httpServletRequest.getHeader("x-amz-sns-message-type");
        String topicArn = httpServletRequest.getHeader("x-amz-sns-topic-arn");
        if(!StringUtils.isEmpty(messageType)){
            if("SubscriptionConfirmation".equals(messageType)){
                activateSNSSubscriptionUnSubscription(requestBody, messageType, topicArn, "SubscribeURL");
            } else if("UnsubscribeConfirmation".equals(messageType)){
                activateSNSSubscriptionUnSubscription(requestBody, messageType, topicArn, "UnsubscribeURL");
            }
        }
    }

    private void activateSNSSubscriptionUnSubscription(String requestBody, final String messageType, String topicArn, String subscribeUnsubscribeURLKey) {
        log.info(messageType + " payload: {}", requestBody);
        JsonMapper mapper = JsonMapper.builder()
                .configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES, true)
                .build();
        try {
            Map<String, String> maps = mapper.readValue(requestBody, new TypeReference<Map<String, String>>() {
            });
            String subscribeUnsubscribeURL = maps.get(subscribeUnsubscribeURLKey);
            RestTemplate restTemplate = new RestTemplate();
//Manually activating the subscribe and UnsubscribeURL requests by making direct HTTP call using rest controller
            ResponseEntity<Void> response = restTemplate.exchange(subscribeUnsubscribeURL, HttpMethod.GET, null, Void.class);
            if (response.getStatusCode().is2xxSuccessful())
                log.info("topicArn: {} messageType: {} Successful: {}", topicArn, messageType, response.getStatusCode());
            else {
                log.error("topicArn: {} messageType: {} failure Status: {}", topicArn, messageType, response.getStatusCode());
            }
        } catch (JsonProcessingException e){
            log.error("topicArn: {} messageType: {} failure error: {}", topicArn, messageType, e.getMessage());
        }catch(HttpClientErrorException e) {
            log.error("topicArn: {} messageType: {} failure error: {}", topicArn, messageType, e.getResponseBodyAsString());
        }
    }
}

控制器的处理程序方法处理 Notification (消息类型),因为其余两个messageTypes由SNSSubscriptionUnSubscriptionActivation处理,作为带有@SNSSubscriptionUnSubscriptionConfirmation()注释的请求处理程序方法。

@Slf4j
@RestController
public class AWSSNSConsumerController {

    @PostMapping(value = "subscribed-endpoint", consumes = MediaType.TEXT_PLAIN_VALUE)
    @SNSSubscriptionUnSubscriptionConfirmation()
    public ResponseEntity<Void> notification(HttpServletRequest httpServletRequest, @RequestBody() String requestBody) {
        log.info("Notification payload: {}", requestBody);
        String topicArn = httpServletRequest.getHeader("x-amz-sns-topic-arn");
        String messageType = httpServletRequest.getHeader("x-amz-sns-message-type");
        if ("Notification".equals(messageType)) {
            JsonMapper mapper = JsonMapper.builder()
                    .configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES, true)
                    .build();
            try {
                Map<String, String> maps = mapper.readValue(requestBody, new TypeReference<Map<String, String>>() {
                });
                String message = maps.get("Message");
                log.info("topic : {} message: {} ", topicArn, message);
            } catch (JsonProcessingException e) {
                log.error("topic : {} Notification failure error: {}", topicArn, e.getMessage());
            } catch (HttpClientErrorException e) {
                log.error("topic : {} Notification failure error: {}", topicArn, e.getResponseBodyAsString());
            }
        }
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

如果您使用的是 spring-cloud-aws ,请遵循此出色的tutorial