使用 AWS Pinpoint 和 Lambda 设置 SMS 注册系统
Setting up a SMS Registration System with AWS Pinpoint & Lambda
我正在尝试使用 AWS Pinpoint、Lambda、API 网关和 SNS 设置 SMS 注册系统。但是,每当我尝试使用 ajax 和他们的示例处理数据时,每次都会出错。
我已经按照此处的指南设置了整个系统:https://docs.aws.amazon.com/pinpoint/latest/developerguide/tutorials-two-way-sms.html
我已经在 AWS 中测试了这两个 Lambda 函数,它们运行良好。但是,当我通过表单发送数据时,我看不到正在发送 API 请求。
这是HTML:
<!doctype html>
<html lang="en">
<head>
<!-- Meta tags required by Bootstrap -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="SMSFormHandler.js"></script>
<title>SMS Registration Form</title>
</head>
<body>
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-md-6">
<h1>Register for SMS Alerts</h1>
<p>Enter your phone number below to sign up for PromotionName messages from ExampleCorp.</p>
<p>We don't share your contact information with anyone else. For more information, see our <a href="http://example.com/privacy">Privacy Policy</a>.</p>
<p>ExampleCorp alerts are only available to recipients in the United States.</p>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<form>
<div class="form-group">
<label for="firstName" class="font-weight-bold">First name</label>
<input type="text" class="form-control" id="firstName" placeholder="Your first name" required>
</div>
<div class="form-group">
<label for="lastName" class="font-weight-bold">Last name</label>
<input type="text" class="form-control" id="lastName" placeholder="Your last name" required>
</div>
<label for="areaCode" class="font-weight-bold">Phone number</label>
<div class="input-group">
<span class="h3">( </span>
<input type="tel" class="form-control" id="areaCode" placeholder="Area code" required>
<span class="h3"> ) </span>
<input type="tel" class="form-control" id="phone1" placeholder="555" required>
<span class="h3"> - </span>
<input type="tel" class="form-control" id="phone2" placeholder="0199" required>
</div>
<div id="form-response"></div>
<button id="submit" type="submit" class="btn btn-primary btn-block mt-3">Submit</button>
</form>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12 text-center">
<small class="text-muted">Copyright © 2019, ExampleCorp or its affiliates.</small>
</div>
</div>
</div>
</body>
</html>
还有Javascript(我已经编辑了API):
$(document).ready(function() {
// Handle form submission.
$("#submit").click(function(e) {
var firstName = $("#firstName").val(),
lastName = $("#lastName").val(),
source = window.location.pathname,
optTimestamp = undefined,
utcSeconds = Date.now() / 1000,
timestamp = new Date(0),
phone = $("#areaCode").val()
+ $("#phone1").val()
+ $("#phone2").val();
e.preventDefault();
if (firstName == "") {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your first name.</div>');
} else if (lastName == "") {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your last name.</div>');
} else if (phone.match(/[^0-9]/gi)) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Your phone number contains invalid characters. Please check the phone number that you supplied.</div>');
} else if (phone.length < 10) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your phone number.</div>');
} else if (phone.length > 10) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Your phone number contains too many digits. Please check the phone number that you supplied.</div>');
} else {
$('#submit').prop('disabled', true);
$('#submit').html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Saving your preferences</button>');
timestamp.setUTCSeconds(utcSeconds);
var data = JSON.stringify({
'destinationNumber': phone,
'firstName': firstName,
'lastName': lastName,
'source': source,
});
$.ajax({
type: 'POST',
url: 'https://############.execute-api.us-east-1.amazonaws.com/v1/register',
contentType: 'application/json',
data: data,
success: function(res) {
$('#form-response').html('<div class="mt-3 alert alert-success" role="alert"><p>Congratulations! You've successfully registered for SMS Alerts from ExampleCorp.</p><p>We just sent you a message. Follow the instructions in the message to confirm your subscription. We won't send any additional messages until we receive your confirmation.</p><p>If you decide you don't want to receive any additional messages from us, just reply to one of our messages with the keyword STOP.</p></div>');
$('#submit').prop('hidden', true);
$('#unsubAll').prop('hidden', true);
$('#submit').text('Preferences saved!');
},
error: function(jqxhr, status, exception) {
$('#form-response').html('<div class="mt-3 alert alert-danger" role="alert">An error occurred. Please try again later.</div>');
$('#submit').text('Save preferences');
$('#submit').prop('disabled', false);
}
});
}
});
});
AWS Lambda 函数:
var AWS = require('aws-sdk');
var pinpoint = new AWS.Pinpoint({region: process.env.region});
// Make sure the SMS channel is enabled for the projectId that you specify.
// See: https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-sms-setup.html
var projectId = process.env.projectId;
// You need a dedicated long code in order to use two-way SMS.
// See: https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-voice-manage.html#channels-voice-manage-request-phone-numbers
var originationNumber = process.env.originationNumber;
// This message is spread across multiple lines for improved readability.
var message = "ExampleCorp: Reply YES to confirm your subscription. 2 msgs per "
+ "month. No purchase req'd. Msg&data rates may apply. Terms: "
+ "example.com/terms-sms";
var messageType = "TRANSACTIONAL";
exports.handler = (event, context, callback) => {
console.log('Received event:', event);
validateNumber(event);
};
function validateNumber (event) {
var destinationNumber = event.destinationNumber;
if (destinationNumber.length == 10) {
destinationNumber = "+1" + destinationNumber;
}
var params = {
NumberValidateRequest: {
IsoCountryCode: 'US',
PhoneNumber: destinationNumber
}
};
pinpoint.phoneNumberValidate(params, function(err, data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
//return data;
if (data['NumberValidateResponse']['PhoneTypeCode'] == 0) {
createEndpoint(data, event.firstName, event.lastName, event.source);
} else {
console.log("Received a phone number that isn't capable of receiving "
+"SMS messages. No endpoint created.");
}
}
});
}
function createEndpoint(data, firstName, lastName, source) {
var destinationNumber = data['NumberValidateResponse']['CleansedPhoneNumberE164'];
var endpointId = data['NumberValidateResponse']['CleansedPhoneNumberE164'].substring(1);
var params = {
ApplicationId: projectId,
// The Endpoint ID is equal to the cleansed phone number minus the leading
// plus sign. This makes it easier to easily update the endpoint later.
EndpointId: endpointId,
EndpointRequest: {
ChannelType: 'SMS',
Address: destinationNumber,
// OptOut is set to ALL (that is, endpoint is opted out of all messages)
// because the recipient hasn't confirmed their subscription at this
// point. When they confirm, a different Lambda function changes this
// value to NONE (not opted out).
OptOut: 'ALL',
Location: {
PostalCode:data['NumberValidateResponse']['ZipCode'],
City:data['NumberValidateResponse']['City'],
Country:data['NumberValidateResponse']['CountryCodeIso2'],
},
Demographic: {
Timezone:data['NumberValidateResponse']['Timezone']
},
Attributes: {
Source: [
source
]
},
User: {
UserAttributes: {
FirstName: [
firstName
],
LastName: [
lastName
]
}
}
}
};
pinpoint.updateEndpoint(params, function(err,data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
//return data;
sendConfirmation(destinationNumber);
}
});
}
function sendConfirmation(destinationNumber) {
var params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[destinationNumber]: {
ChannelType: 'SMS'
}
},
MessageConfiguration: {
SMSMessage: {
Body: message,
MessageType: messageType,
OriginationNumber: originationNumber
}
}
}
};
pinpoint.sendMessages(params, function(err, data) {
// If something goes wrong, print an error message.
if(err) {
console.log(err.message);
// Otherwise, show the unique ID for the message.
} else {
console.log("Message sent! "
+ data['MessageResponse']['Result'][destinationNumber]['StatusMessage']);
}
});
}
为 originationNumber、projectId 和 region 设置了环境变量。
我期待它向 REST API 发送请求,这会触发 Lambda 函数发送 SMS 消息。但是,它并没有最终发送请求。我还尝试过使用 Postman 进行一般 REST API 测试,然后在 Lambda 函数中出现错误。我使用 REST API 测试网站进行测试,它说它正在报告 HTTP 0 错误。它提到要确保我启用了 CORS,并且我已经在我的 API 上启用了它。
有什么想法请告诉我!
谢谢。
我的回答依赖于您将 API 网关配置为 Lambda 代理集成 的假设。
根据您的错误示例,我可以看到
validateNumber 函数内部有问题。
您的数据在 event.body 内而不是在事件内。
变化:
var destinationNumber = event.destinationNumber
收件人:
const body = JSON.parse(event.body)
var destinationNumber = body.destinationNumber
如果您需要更多信息,请告诉我。
希望对您有所帮助
基本上,我的 REST API 上的 CORS 导致了问题。所以我把它删除了。
现在,我的 API 终于可以接受请求了。但是,测试 AWS 功能不再起作用。我最后添加了以下 try-catch 语句来解析 JSON 数据,如果它没有给出错误的话:
try {
event = JSON.parse(event.body);
} catch (e) {
event = event.body;
}
我正在尝试使用 AWS Pinpoint、Lambda、API 网关和 SNS 设置 SMS 注册系统。但是,每当我尝试使用 ajax 和他们的示例处理数据时,每次都会出错。
我已经按照此处的指南设置了整个系统:https://docs.aws.amazon.com/pinpoint/latest/developerguide/tutorials-two-way-sms.html
我已经在 AWS 中测试了这两个 Lambda 函数,它们运行良好。但是,当我通过表单发送数据时,我看不到正在发送 API 请求。
这是HTML:
<!doctype html>
<html lang="en">
<head>
<!-- Meta tags required by Bootstrap -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="SMSFormHandler.js"></script>
<title>SMS Registration Form</title>
</head>
<body>
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-md-6">
<h1>Register for SMS Alerts</h1>
<p>Enter your phone number below to sign up for PromotionName messages from ExampleCorp.</p>
<p>We don't share your contact information with anyone else. For more information, see our <a href="http://example.com/privacy">Privacy Policy</a>.</p>
<p>ExampleCorp alerts are only available to recipients in the United States.</p>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<form>
<div class="form-group">
<label for="firstName" class="font-weight-bold">First name</label>
<input type="text" class="form-control" id="firstName" placeholder="Your first name" required>
</div>
<div class="form-group">
<label for="lastName" class="font-weight-bold">Last name</label>
<input type="text" class="form-control" id="lastName" placeholder="Your last name" required>
</div>
<label for="areaCode" class="font-weight-bold">Phone number</label>
<div class="input-group">
<span class="h3">( </span>
<input type="tel" class="form-control" id="areaCode" placeholder="Area code" required>
<span class="h3"> ) </span>
<input type="tel" class="form-control" id="phone1" placeholder="555" required>
<span class="h3"> - </span>
<input type="tel" class="form-control" id="phone2" placeholder="0199" required>
</div>
<div id="form-response"></div>
<button id="submit" type="submit" class="btn btn-primary btn-block mt-3">Submit</button>
</form>
</div>
</div>
<div class="row mt-3">
<div class="col-md-12 text-center">
<small class="text-muted">Copyright © 2019, ExampleCorp or its affiliates.</small>
</div>
</div>
</div>
</body>
</html>
还有Javascript(我已经编辑了API):
$(document).ready(function() {
// Handle form submission.
$("#submit").click(function(e) {
var firstName = $("#firstName").val(),
lastName = $("#lastName").val(),
source = window.location.pathname,
optTimestamp = undefined,
utcSeconds = Date.now() / 1000,
timestamp = new Date(0),
phone = $("#areaCode").val()
+ $("#phone1").val()
+ $("#phone2").val();
e.preventDefault();
if (firstName == "") {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your first name.</div>');
} else if (lastName == "") {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your last name.</div>');
} else if (phone.match(/[^0-9]/gi)) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Your phone number contains invalid characters. Please check the phone number that you supplied.</div>');
} else if (phone.length < 10) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Please enter your phone number.</div>');
} else if (phone.length > 10) {
$('#form-response').html('<div class="mt-3 alert alert-info" role="alert">Your phone number contains too many digits. Please check the phone number that you supplied.</div>');
} else {
$('#submit').prop('disabled', true);
$('#submit').html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Saving your preferences</button>');
timestamp.setUTCSeconds(utcSeconds);
var data = JSON.stringify({
'destinationNumber': phone,
'firstName': firstName,
'lastName': lastName,
'source': source,
});
$.ajax({
type: 'POST',
url: 'https://############.execute-api.us-east-1.amazonaws.com/v1/register',
contentType: 'application/json',
data: data,
success: function(res) {
$('#form-response').html('<div class="mt-3 alert alert-success" role="alert"><p>Congratulations! You've successfully registered for SMS Alerts from ExampleCorp.</p><p>We just sent you a message. Follow the instructions in the message to confirm your subscription. We won't send any additional messages until we receive your confirmation.</p><p>If you decide you don't want to receive any additional messages from us, just reply to one of our messages with the keyword STOP.</p></div>');
$('#submit').prop('hidden', true);
$('#unsubAll').prop('hidden', true);
$('#submit').text('Preferences saved!');
},
error: function(jqxhr, status, exception) {
$('#form-response').html('<div class="mt-3 alert alert-danger" role="alert">An error occurred. Please try again later.</div>');
$('#submit').text('Save preferences');
$('#submit').prop('disabled', false);
}
});
}
});
});
AWS Lambda 函数:
var AWS = require('aws-sdk');
var pinpoint = new AWS.Pinpoint({region: process.env.region});
// Make sure the SMS channel is enabled for the projectId that you specify.
// See: https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-sms-setup.html
var projectId = process.env.projectId;
// You need a dedicated long code in order to use two-way SMS.
// See: https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-voice-manage.html#channels-voice-manage-request-phone-numbers
var originationNumber = process.env.originationNumber;
// This message is spread across multiple lines for improved readability.
var message = "ExampleCorp: Reply YES to confirm your subscription. 2 msgs per "
+ "month. No purchase req'd. Msg&data rates may apply. Terms: "
+ "example.com/terms-sms";
var messageType = "TRANSACTIONAL";
exports.handler = (event, context, callback) => {
console.log('Received event:', event);
validateNumber(event);
};
function validateNumber (event) {
var destinationNumber = event.destinationNumber;
if (destinationNumber.length == 10) {
destinationNumber = "+1" + destinationNumber;
}
var params = {
NumberValidateRequest: {
IsoCountryCode: 'US',
PhoneNumber: destinationNumber
}
};
pinpoint.phoneNumberValidate(params, function(err, data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
//return data;
if (data['NumberValidateResponse']['PhoneTypeCode'] == 0) {
createEndpoint(data, event.firstName, event.lastName, event.source);
} else {
console.log("Received a phone number that isn't capable of receiving "
+"SMS messages. No endpoint created.");
}
}
});
}
function createEndpoint(data, firstName, lastName, source) {
var destinationNumber = data['NumberValidateResponse']['CleansedPhoneNumberE164'];
var endpointId = data['NumberValidateResponse']['CleansedPhoneNumberE164'].substring(1);
var params = {
ApplicationId: projectId,
// The Endpoint ID is equal to the cleansed phone number minus the leading
// plus sign. This makes it easier to easily update the endpoint later.
EndpointId: endpointId,
EndpointRequest: {
ChannelType: 'SMS',
Address: destinationNumber,
// OptOut is set to ALL (that is, endpoint is opted out of all messages)
// because the recipient hasn't confirmed their subscription at this
// point. When they confirm, a different Lambda function changes this
// value to NONE (not opted out).
OptOut: 'ALL',
Location: {
PostalCode:data['NumberValidateResponse']['ZipCode'],
City:data['NumberValidateResponse']['City'],
Country:data['NumberValidateResponse']['CountryCodeIso2'],
},
Demographic: {
Timezone:data['NumberValidateResponse']['Timezone']
},
Attributes: {
Source: [
source
]
},
User: {
UserAttributes: {
FirstName: [
firstName
],
LastName: [
lastName
]
}
}
}
};
pinpoint.updateEndpoint(params, function(err,data) {
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
//return data;
sendConfirmation(destinationNumber);
}
});
}
function sendConfirmation(destinationNumber) {
var params = {
ApplicationId: projectId,
MessageRequest: {
Addresses: {
[destinationNumber]: {
ChannelType: 'SMS'
}
},
MessageConfiguration: {
SMSMessage: {
Body: message,
MessageType: messageType,
OriginationNumber: originationNumber
}
}
}
};
pinpoint.sendMessages(params, function(err, data) {
// If something goes wrong, print an error message.
if(err) {
console.log(err.message);
// Otherwise, show the unique ID for the message.
} else {
console.log("Message sent! "
+ data['MessageResponse']['Result'][destinationNumber]['StatusMessage']);
}
});
}
为 originationNumber、projectId 和 region 设置了环境变量。
我期待它向 REST API 发送请求,这会触发 Lambda 函数发送 SMS 消息。但是,它并没有最终发送请求。我还尝试过使用 Postman 进行一般 REST API 测试,然后在 Lambda 函数中出现错误。我使用 REST API 测试网站进行测试,它说它正在报告 HTTP 0 错误。它提到要确保我启用了 CORS,并且我已经在我的 API 上启用了它。
有什么想法请告诉我!
谢谢。
我的回答依赖于您将 API 网关配置为 Lambda 代理集成 的假设。 根据您的错误示例,我可以看到 validateNumber 函数内部有问题。 您的数据在 event.body 内而不是在事件内。
变化:
var destinationNumber = event.destinationNumber
收件人:
const body = JSON.parse(event.body)
var destinationNumber = body.destinationNumber
如果您需要更多信息,请告诉我。
希望对您有所帮助
基本上,我的 REST API 上的 CORS 导致了问题。所以我把它删除了。
现在,我的 API 终于可以接受请求了。但是,测试 AWS 功能不再起作用。我最后添加了以下 try-catch 语句来解析 JSON 数据,如果它没有给出错误的话:
try {
event = JSON.parse(event.body);
} catch (e) {
event = event.body;
}