정적 사이트를 위한 서버리스 문의 양식 작성
게시 됨: 2022-03-10정적 사이트 생성기는 WordPress와 같은 콘텐츠 관리 시스템(CMS)에 대한 빠르고 간단한 대안을 제공합니다. 서버나 데이터베이스 설정이 없고 빌드 프로세스와 간단한 HTML, CSS 및 JavaScript만 있습니다. 불행히도 서버가 없으면 한계에 빨리 도달하기 쉽습니다. 예를 들어, 연락처 양식을 추가합니다.
서버리스 아키텍처의 등장으로 정적 사이트에 문의 양식을 추가하는 것이 더 이상 CMS로 전환해야 하는 이유가 될 필요가 없습니다. 두 세계의 장점을 모두 얻을 수 있습니다. 연락처 양식에 대한 서버리스 백엔드가 있는 정적 사이트(유지 관리할 필요가 없음). 무엇보다도 포트폴리오와 같이 트래픽이 적은 사이트에서 많은 서버리스 공급자의 높은 제한으로 인해 이러한 서비스가 완전히 무료입니다!
이 문서에서는 Serverless Framework에서 고유한 정적 사이트 메일러를 구축하기 위한 Amazon Web Services(AWS) Lambda 및 SES(Simple Email Service) API의 기본 사항을 배웁니다. 전체 서비스는 AJAX 요청에서 제출된 데이터 형식을 취하고, Lambda 엔드포인트에 도달하고, 데이터를 구문 분석하여 SES 매개변수를 구축하고, 이메일 주소를 보내고, 사용자에게 응답을 반환합니다. 배포를 통해 처음으로 Serverless를 설정하는 방법을 안내해 드리겠습니다. 완료하는 데 1시간 미만이 소요되므로 시작하겠습니다!
설정
서버리스 기술을 시작하기 위한 최소한의 전제 조건이 있습니다. 여기서는 단순히 Yarn, Serverless Framework 및 AWS 계정이 있는 노드 환경입니다.
프로젝트 설정
Yarn을 사용하여 Serverless Framework를 로컬 디렉토리에 설치합니다.
- 프로젝트를 호스팅할 새 디렉터리를 만듭니다.
- 명령줄 인터페이스에서 디렉터리로 이동합니다.
-
yarn init
를 실행하여 이 프로젝트에 대한package.json
파일을 만듭니다. -
yarn add serverless
를 실행하여 프레임워크를 로컬에 설치합니다. -
yarn serverless create --template aws-nodejs --name static-site-mailer
를 실행하여 노드 서비스 템플릿을 생성하고 이름을static-site-mailer
지정합니다.
프로젝트가 설정되었지만 AWS 서비스를 설정할 때까지 아무 것도 할 수 없습니다.
Amazon Web Services 계정, 자격 증명 및 간단한 이메일 서비스 설정
Serverless Framework는 AWS 자격 증명을 설정하기 위한 비디오 연습을 녹화했지만 여기에도 단계가 나열되어 있습니다.
- AWS 계정에 가입하거나 이미 계정이 있는 경우 로그인합니다.
- AWS 검색 창에서 "IAM"을 검색합니다.
- IAM 페이지의 사이드바에서 "사용자"를 클릭한 다음 "사용자 추가" 버튼을 클릭합니다.
- 사용자 추가 페이지에서 "서버리스"와 같은 이름이 적절합니다. 액세스 유형에서 "프로그래매틱 액세스"를 선택하고 다음을 클릭합니다.
- 권한 화면에서 "기존 정책 직접 연결" 탭을 클릭하고 목록에서 "AdministratorAccess"를 검색하여 확인하고 다음을 클릭합니다.
- 검토 화면에서 "프로그래밍 방식 액세스" 및 "AdministratorAccess"가 포함된 사용자 이름을 확인한 다음 사용자를 생성해야 합니다.
- 확인 화면에 사용자 "액세스 키 ID" 및 "비밀 액세스 키"가 표시됩니다. Serverless Framework에 액세스 권한을 제공하려면 이러한 정보가 필요합니다. CLI에서
yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEY
를 입력하고YOUR_ACCESS_KEY_ID
및YOUR_SECRET_ACCESS_KEY
를 확인 화면의 키로 대체합니다.
이제 자격 증명이 구성되었지만 AWS 콘솔에 있는 동안 Simple Email Service를 설정하겠습니다.
- 왼쪽 상단 모서리에 있는 콘솔 홈을 클릭하여 집으로 이동합니다.
- 홈 페이지의 AWS 검색 창에서 "Simple Email Service"를 검색합니다.
- SES 홈 페이지의 사이드바에서 "이메일 주소"를 클릭하십시오.
- 이메일 주소 목록 페이지에서 "새 이메일 주소 확인" 버튼을 클릭합니다.
- 대화 상자 창에서 이메일 주소를 입력한 다음 "이 이메일 주소 확인"을 클릭합니다.
- 주소를 확인할 수 있는 링크가 포함된 이메일을 곧 받게 됩니다. 링크를 클릭하여 프로세스를 완료하십시오.
이제 계정이 만들어졌으므로 Serverless 템플릿 파일을 살펴보겠습니다.
서버리스 프레임워크 설정
serverless create
를 실행하면 Lambda 함수가 포함된 handler.js와 전체 서버리스 아키텍처에 대한 구성 파일인 serverless.yml이라는 두 개의 파일이 생성됩니다. 구성 파일 내에서 원하는 만큼 핸들러를 지정할 수 있으며 각 핸들러는 다른 기능과 상호 작용할 수 있는 새 기능에 매핑됩니다. 이 프로젝트에서는 단일 처리기를 만들지만 전체 서버리스 아키텍처에서는 서비스의 다양한 기능 중 몇 가지를 갖게 됩니다.
handler.js에서 hello
라는 단일 내보낸 함수를 볼 수 있습니다. 이것은 현재 주요(유일한) 기능입니다. 모든 노드 핸들러와 함께 세 가지 매개변수를 사용합니다.
-
event
이것은 함수에 대한 입력 데이터로 생각할 수 있습니다. -
context object
여기에는 Lambda 함수의 런타임 정보가 포함됩니다. -
callback
호출자에게 정보를 반환하는 선택적 매개변수입니다.
// handler.js 'use strict'; module.exports.hello = (event, context, callback) => { const response = { statusCode: 200, body: JSON.stringify({ message: 'Go Serverless v1.0! Your function executed successfully!', input: event, }), }; callback(null, response); };
hello
의 맨 아래에 콜백이 있습니다. 응답을 반환하는 선택적 인수이지만 명시적으로 호출되지 않으면 암시적 으로 null
을 반환합니다. 콜백은 두 개의 매개변수를 사용합니다.
- 오류 오류
Lambda 자체가 실패하는 경우에 대한 오류 정보를 제공합니다. Lambda가 성공하면null
이 이 매개변수에 전달되어야 합니다. - 개체 결과
응답 객체를 제공합니다.JSON.stringify
와 호환되어야 합니다. 오류 필드에 매개변수가 있는 경우 이 필드는 무시됩니다.
정적 사이트는 이벤트 본문에 양식 데이터를 보내고 콜백은 사용자가 볼 수 있도록 응답을 반환합니다.
serverless.yml에서 서비스 이름, 공급자 정보 및 기능을 볼 수 있습니다.
# serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: hello: handler: handler.hello
hello 함수와 핸들러 간의 매핑을 확인하시겠습니까? 파일과 기능의 이름을 지정할 수 있으며 구성에 매핑되는 한 작동합니다. 함수의 이름을 staticSiteMailer
로 바꾸겠습니다.
# serverless.yml functions: staticSiteMailer: handler: handler.staticSiteMailer
// handler.js module.exports.staticSiteMailer = (event, context, callback) => { ... };
Lambda 함수는 다른 AWS 인프라와 상호 작용할 수 있는 권한이 필요합니다. 이메일을 보내기 전에 SES가 이메일을 보낼 수 있도록 허용해야 합니다. serverless.yml의 provider.iamRoleStatements
에서 권한을 추가합니다.
# serverless.yml provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]
양식 작업에 대한 URL이 필요하므로 함수에 HTTP 이벤트를 추가해야 합니다. serverless.yml에서 경로를 만들고 메서드를 post
로 지정하고 보안을 위해 CORS를 true로 설정합니다.
functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true
업데이트된 serverless.yml 및 handler.js 파일은 다음과 같아야 합니다.
# serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]
// handler.js 'use strict'; module.exports.staticSiteMailer = (event, context, callback) => { const response = { statusCode: 200, body: JSON.stringify({ message: 'Go Serverless v1.0! Your function executed successfully!', input: event, }), }; callback(null, response); };
서버리스 아키텍처가 설정되었으므로 배포하고 테스트해 보겠습니다. 간단한 JSON 응답을 받게 됩니다.
yarn sls deploy --verbose yarn sls invoke --function staticSiteMailer { "statusCode": 200, "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}" }
HTML 양식 만들기
Lambda 함수 입력과 양식 출력은 일치해야 하므로 함수를 빌드하기 전에 양식을 빌드하고 출력을 캡처합니다. 이름, 이메일 및 메시지 필드를 사용하여 간단하게 유지합니다. 서버리스 아키텍처를 배포하고 URL을 얻은 후에는 양식 작업을 추가하지만 추가할 수 있도록 POST 요청이 될 것임을 알고 있습니다. 양식 끝에 표시할 단락 태그를 추가합니다. 제출 콜백에서 업데이트할 사용자에 대한 응답 메시지입니다.
<form action="{{ SERVICE URL }}" method="POST"> <label> Name <input type="text" name="name" required> </label> <label> Email <input type="email" name="reply_to" required> </label> <label> Message: <textarea name="message" required></textarea> </label> <button type="submit">Send Message</button> </form> <p></p>
출력을 캡처하기 위해 양식에 제출 핸들러를 추가하고 양식 매개변수를 객체로 바꾸고 문자열화된 JSON을 Lambda 함수로 보냅니다. Lambda 함수에서 JSON.parse()
를 사용하여 데이터를 읽습니다. 또는 jQuery의 직렬화 또는 쿼리 문자열을 사용하여 양식 매개변수를 쿼리 문자열로 보내고 구문 분석할 수 있지만 JSON.stringify()
및 JSON.parse()
는 기본입니다.
(() => { const form = document.querySelector('form'); const formResponse = document.querySelector('js-form-response'); form.onsubmit = e => { e.preventDefault(); // Prepare data to send const data = {}; const formElements = Array.from(form); formElements.map(input => (data[input.name] = input.value)); // Log what our lambda function will receive console.log(JSON.stringify(data)); }; })();
계속해서 양식을 제출한 다음 콘솔 출력을 캡처하십시오. 다음에 Lambda 함수에서 사용하겠습니다.
Lambda 함수 호출
특히 개발 중에 기능이 기대한 대로 작동하는지 테스트해야 합니다. Serverless Framework는 각각 라이브 및 개발 환경에서 함수를 트리거하는 invoke
및 invoke local
명령을 제공합니다. 두 명령 모두 전달된 함수 이름이 필요합니다(이 경우 staticSiteMailer
.
yarn sls invoke local --function staticSiteMailer
모의 데이터를 함수에 전달하려면 JSON 개체 내의 body
키 아래에 캡처된 콘솔 출력을 사용하여 data.json
이라는 새 파일을 만듭니다. 다음과 같아야 합니다.
// data.json { "body": "{\"name\": \"Sender Name\",\"reply_to\": \"[email protected]\",\"message\": \"Sender message\"}" }
로컬 데이터로 함수를 호출하려면 파일 경로와 함께 --path
인수를 전달하십시오.
yarn sls invoke local --function staticSiteMailer --path data.json
이전과 비슷한 응답을 볼 수 있지만 input
키에는 우리가 조롱한 이벤트가 포함됩니다. Simple Email Service를 사용하여 이메일을 보내기 위해 모의 데이터를 사용합시다!
Simple Email Service로 이메일 보내기
staticSiteMailer
함수를 private sendEmail
함수에 대한 호출로 교체할 것입니다. 지금은 템플릿 코드를 주석 처리하거나 제거하고 다음으로 대체할 수 있습니다.
// hander.js function sendEmail(formData, callback) { // Build the SES parameters // Send the email } module.exports.staticSiteMailer = (event, context, callback) => { const formData = JSON.parse(event.body); sendEmail(formData, function(err, data) { if (err) { console.log(err, err.stack); } else { console.log(data); } }); };
먼저 event.body
를 구문 분석하여 양식 데이터를 캡처한 다음 개인 sendEmail
함수에 전달합니다. sendEmail
은 이메일 전송을 담당하며 콜백 함수는 err
또는 data
와 함께 실패 또는 성공 응답을 반환합니다. 우리의 경우 잠시 후 이를 Lambda 콜백으로 교체할 것이기 때문에 오류나 데이터를 간단히 기록할 수 있습니다.
Amazon은 서비스를 Lambda 함수와 연결하기 위한 편리한 SDK인 aws-sdk
를 제공합니다. SES를 포함한 많은 서비스가 그 일부입니다. yarn add aws-sdk
를 사용하여 프로젝트에 추가하고 핸들러 파일 상단으로 가져옵니다.
// handler.js const AWS = require('aws-sdk'); const SES = new AWS.SES();
개인 sendEmail
함수에서 구문 분석된 양식 데이터에서 SES.sendEmail
매개변수를 만들고 콜백을 사용하여 호출자에게 응답을 반환합니다. 매개변수에는 객체로 다음이 필요합니다.
- 원천
SES 가 보내는 이메일 주소 . - 회신 주소
이메일의 필드에 대한 회신에 추가된 이메일 주소 배열입니다. - 목적지
하나 이상의 ToAddresses , CcAddresses 또는 BccAddresses 를 포함해야 하는 개체입니다. 각 필드는 각각 to , cc 및 bcc 필드에 해당하는 이메일 주소 배열을 사용합니다. - 메세지
Body 및 Subject 를 포함하는 객체입니다.
formData
는 객체이기 때문에 formData.message
와 같이 직접 양식 필드를 호출하고 매개변수를 빌드하여 보낼 수 있습니다. SES 확인 이메일을 Source
및 Destination.ToAddresses
로 전달 합니다 . 이메일이 확인되면 다른 이메일 주소를 포함하여 무엇이든 전달할 수 있습니다. 우리는 ReplyToAddresses
및 Message.Body.Text.Data
필드를 채우기 위해 formData
객체에서 reply_to
, message
및 name
을 뽑습니다.
// handler.js function sendEmail(formData, callback) { const emailParams = { Source: '[email protected]', // SES SENDING EMAIL ReplyToAddresses: [formData.reply_to], Destination: { ToAddresses: ['[email protected]'], // SES RECEIVING EMAIL }, Message: { Body: { Text: { Charset: 'UTF-8', Data: `${formData.message}\n\nName: ${formData.name}\nEmail: ${formData.reply_to}`, }, }, Subject: { Charset: 'UTF-8', Data: 'New message from your_site.com', }, }, }; SES.sendEmail(emailParams, callback); }
SES.sendEmail
은 이메일을 보내고 우리의 콜백은 응답을 반환합니다. 로컬 기능을 호출하면 확인된 주소로 이메일이 전송됩니다.
yarn sls invoke local --function staticSiteMailer --path data.json
핸들러에서 응답 반환
우리 함수는 명령줄을 사용하여 이메일을 보내지만 사용자가 이메일과 상호 작용하는 방식은 아닙니다. AJAX 양식 제출에 대한 응답을 반환해야 합니다. 실패하면 적절한 statusCode
와 err.message
를 반환해야 합니다. 성공하면 statusCode
200
이면 충분하지만 본문에서도 메일러 응답을 반환합니다. staticSiteMailer
에서 응답 데이터를 구축하고 sendEmail
콜백 함수를 Lambda 콜백으로 바꿉니다.
// handler.js module.exports.staticSiteMailer = (event, context, callback) => { const formData = JSON.parse(event.body); sendEmail(formData, function(err, data) { const response = { statusCode: err ? 500 : 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'https://your-domain.com', }, body: JSON.stringify({ message: err ? err.message : data, }), }; callback(null, response); }); };
이제 Lambda 콜백이 SES.sendEmail
에서 성공 및 실패 메시지를 모두 반환합니다. err
이 있는지 확인하여 응답을 빌드하여 응답이 일관성을 유지합니다. Lambda 콜백 함수 자체는 오류 인수 필드에 null
을 전달하고 두 번째로 응답을 전달합니다. 오류를 계속 전달하고 싶지만 Lambda 자체가 실패하면 해당 콜백이 오류 응답과 함께 암시적으로 호출됩니다.
headers
에서 Access-Control-Allow-Origin
을 자신의 도메인으로 바꿔야 합니다. 이렇게 하면 다른 도메인이 귀하의 서비스를 사용하여 잠재적으로 귀하의 이름으로 AWS 청구서를 쌓는 것을 방지할 수 있습니다! 이 기사에서는 다루지 않지만 자신의 도메인을 사용하도록 Lambda를 설정할 수 있습니다. Amazon에 업로드된 SSL/TLS 인증서가 있어야 합니다. Serverless Framework 팀은 그렇게 하는 방법에 대한 환상적인 튜토리얼을 작성했습니다.
이제 로컬 기능을 호출하면 이메일이 전송되고 적절한 응답이 반환됩니다.
yarn sls invoke local --function staticSiteMailer --path data.json
양식에서 Lambda 함수 호출
우리의 서비스가 완료되었습니다! 이를 배포하려면 yarn sls deploy -v
를 실행합니다. 배포되면 양식 작업에 추가할 수 있는 https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailer
와 같은 URL을 얻게 됩니다. 다음으로 AJAX 요청을 생성하고 사용자에게 응답을 반환합니다.
(() => { const form = document.querySelector('form'); const formResponse = document.querySelector('js-form-response'); form.onsubmit = e => { e.preventDefault(); // Prepare data to send const data = {}; const formElements = Array.from(form); formElements.map(input => (data[input.name] = input.value)); // Log what our lambda function will receive console.log(JSON.stringify(data)); // Construct an HTTP request var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action, true); xhr.setRequestHeader('Accept', 'application/json; charset=utf-8'); xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); // Send the collected data as JSON xhr.send(JSON.stringify(data)); // Callback function xhr.onloadend = response => { if (response.target.status === 200) { // The form submission was successful form.reset(); formResponse.innerHTML = 'Thanks for the message. I'll be in touch shortly.'; } else { // The form submission failed formResponse.innerHTML = 'Something went wrong'; console.error(JSON.parse(response.target.response).message); } }; }; })();
AJAX 콜백에서 response.target.status
로 상태 코드를 확인합니다. 200
이외의 값이면 사용자에게 오류 메시지를 표시할 수 있습니다. 그렇지 않으면 메시지가 전송되었음을 알립니다. Lambda는 문자열화된 JSON을 반환하므로 JSON.parse(response.target.response).message
를 사용하여 본문 메시지를 구문 분석할 수 있습니다. 특히 오류를 기록하는 데 유용합니다.
정적 사이트에서 완전히 양식을 제출할 수 있어야 합니다!
다음 단계
Serverless Framework 및 AWS를 사용하면 정적에 문의 양식을 쉽게 추가할 수 있습니다. 허니팟으로 양식 유효성 검사를 추가하고 잘못된 양식에 대한 AJAX 호출을 방지하고 응답이 있는 경우 UX를 개선하는 것과 같이 코드에 개선의 여지가 있지만 시작하기에 충분합니다. 내가 만든 정적 사이트 메일러 저장소에서 이러한 개선 사항 중 일부를 볼 수 있습니다. 서버리스를 직접 사용해 보시도록 영감을 주셨기를 바랍니다!