Crearea unui formular de contact fără server pentru site-ul dvs. static
Publicat: 2022-03-10Generatoarele statice de site oferă o alternativă rapidă și simplă la sistemele de management al conținutului (CMS) precum WordPress. Nu există setări de server sau baze de date, doar un proces de construire și HTML, CSS și JavaScript simplu. Din păcate, fără un server, este ușor să-și atingi rapid limitele. De exemplu, în adăugarea unui formular de contact.
Odată cu creșterea arhitecturii fără server, adăugarea unui formular de contact pe site-ul dvs. static nu mai trebuie să fie motivul pentru a trece la un CMS. Este posibil să obțineți tot ce este mai bun din ambele lumi: un site static cu un back-end fără server pentru formularul de contact (pe care nu trebuie să îl întrețineți). Poate cel mai bine, în site-urile cu trafic redus, cum ar fi portofoliile, limitele ridicate ale multor furnizori fără server fac aceste servicii complet gratuite!
În acest articol, veți învăța elementele de bază ale API-urilor Amazon Web Services (AWS) Lambda și Simple Email Service (SES) pentru a vă crea propriul site de e-mail static în cadrul Serverless Framework. Serviciul complet va prelua datele trimise dintr-o solicitare AJAX, va atinge punctul final Lambda, va analiza datele pentru a construi parametrii SES, va trimite adresa de e-mail și va returna un răspuns pentru utilizatorii noștri. Vă voi ghida prin configurarea Serverless pentru prima dată prin implementare. Ar trebui să dureze mai puțin de o oră, așa că să începem!

Configurare
Există cerințe minime pentru a începe cu tehnologia Serverless. Pentru scopurile noastre, este pur și simplu un Node Environment cu Yarn, Serverless Framework și un cont AWS.
Stabilirea Proiectului

Folosim Yarn pentru a instala Serverless Framework într-un director local.
- Creați un director nou pentru a găzdui proiectul.
- Navigați la directorul din interfața de linie de comandă.
- Rulați
yarn init
pentru a crea un fișierpackage.json
pentru acest proiect. - Rulați
yarn add serverless
pentru a instala cadrul local. - Rulați
yarn serverless create --template aws-nodejs --name static-site-mailer
pentru a crea un șablon de serviciu Node și denumește-lstatic-site-mailer
.
Proiectul nostru este configurat, dar nu vom putea face nimic până când nu vom configura serviciile noastre AWS.
Configurarea unui cont Amazon Web Services, acreditărilor și a unui serviciu simplu de e-mail

Serverless Framework a înregistrat o prezentare video pentru configurarea acreditărilor AWS, dar am enumerat și pașii aici.
- Înscrieți-vă pentru un cont AWS sau conectați-vă dacă aveți deja unul.
- În bara de căutare AWS, căutați „IAM”.
- Pe pagina IAM, faceți clic pe „Utilizatori” din bara laterală, apoi pe butonul „Adăugați utilizator”.
- Pe pagina Adăugați utilizator, dați utilizatorului un nume – ceva de genul „fără server” este potrivit. Bifați „Acces programatic” sub Tip de acces, apoi faceți clic pe Următorul.
- Pe ecranul de permisiuni, faceți clic pe fila „Atașați direct politicile existente”, căutați „AdministratorAccess” în listă, verificați-l și faceți clic pe Următorul.
- Pe ecranul de revizuire ar trebui să vedeți numele dvs. de utilizator, cu „Acces programat” și „Acces Administrator”, apoi creați utilizatorul.
- Ecranul de confirmare arată utilizatorului „ID-ul cheii de acces” și „Cheia de acces secretă”, veți avea nevoie de acestea pentru a oferi cadru fără server acces. În CLI, tastați
yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEY
, înlocuindYOUR_ACCESS_KEY_ID
șiYOUR_SECRET_ACCESS_KEY
cu tastele de pe ecranul de confirmare.
Acreditările dvs. sunt configurate acum, dar în timp ce ne aflăm în consola AWS, să setăm Serviciul de e-mail simplu.
- Faceți clic pe Console Home în colțul din stânga sus pentru a merge acasă.
- Pe pagina de pornire, în bara de căutare AWS, căutați „Serviciul simplu de e-mail”.
- Pe pagina de pornire SES, faceți clic pe „Adrese de e-mail” din bara laterală.
- Pe pagina de listă cu adrese de e-mail, faceți clic pe butonul „Verificați o nouă adresă de e-mail”.
- În fereastra de dialog, introduceți adresa de e-mail, apoi faceți clic pe „Verificați această adresă de e-mail”.
- Veți primi în câteva momente un e-mail care conține un link pentru a verifica adresa. Faceți clic pe link pentru a finaliza procesul.
Acum că ne-am făcut conturile, să aruncăm o privire la fișierele șablon Serverless.
Configurarea cadrului fără server
Rularea serverless create
creează două fișiere: handler.js care conține funcția Lambda și serverless.yml, care este fișierul de configurare pentru întreaga arhitectură Serverless. În fișierul de configurare, puteți specifica cât de mulți handleri doriți, iar fiecare va fi mapat la o nouă funcție care poate interacționa cu alte funcții. În acest proiect, vom crea doar un singur handler, dar într-o arhitectură completă fără server, veți avea mai multe dintre diferitele funcții ale serviciului.

În handler.js, veți vedea o singură funcție exportată numită hello
. Aceasta este în prezent funcția principală (și singura). Acesta, împreună cu toți gestionanții Node, iau trei parametri:
-
event
Aceasta poate fi considerată ca fiind datele de intrare pentru funcție. -
context object
Acesta conține informațiile de rulare ale funcției Lambda. -
callback
Un parametru opțional pentru a returna informații apelantului.
// 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); };
În partea de jos a hello
, există un apel invers. Este un argument opțional pentru a returna un răspuns, dar dacă nu este apelat în mod explicit , va reveni implicit cu null
. Reapelarea are doi parametri:
- Eroare eroare
Pentru furnizarea de informații despre eroare atunci când Lambda în sine eșuează. Când Lambda reușește,null
ar trebui să fie trecut în acest parametru. - Rezultatul obiectului
Pentru furnizarea unui obiect de răspuns. Trebuie să fie compatibilJSON.stringify
. Dacă există un parametru în câmpul de eroare, acest câmp este ignorat.
Site-ul nostru static va trimite datele formularului nostru în corpul evenimentului, iar apelul înapoi va returna un răspuns pe care să îl vadă utilizatorul nostru.
În serverless.yml veți vedea numele serviciului, informațiile despre furnizor și funcțiile.
# serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: hello: handler: handler.hello

Observați maparea dintre funcția hello și handler? Ne putem numi fișierul și funcționa orice și atâta timp cât se mapează la configurație, va funcționa. Să redenumim funcția în staticSiteMailer
.
# serverless.yml functions: staticSiteMailer: handler: handler.staticSiteMailer
// handler.js module.exports.staticSiteMailer = (event, context, callback) => { ... };
Funcțiile Lambda au nevoie de permisiunea de a interacționa cu altă infrastructură AWS. Înainte de a putea trimite un e-mail, trebuie să permitem SES să facă acest lucru. În serverless.yml, sub provider.iamRoleStatements
adăugați permisiunea.
# serverless.yml provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]
Deoarece avem nevoie de o adresă URL pentru acțiunea din formular, trebuie să adăugăm evenimente HTTP la funcția noastră. În serverless.yml creăm o cale, specificăm metoda ca post
și setăm CORS la true pentru securitate.
functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true
Fișierele noastre actualizate serverless.yml și handler.js ar trebui să arate astfel:
# 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); };
Arhitectura noastră fără server este configurată, așa că haideți să o implementăm și să o testăm. Veți primi un răspuns simplu JSON.
yarn sls deploy --verbose yarn sls invoke --function staticSiteMailer { "statusCode": 200, "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}" }

Crearea formularului HTML
Intrarea funcției noastre Lambda și ieșirea formularului trebuie să se potrivească, așa că înainte de a construi funcția vom construi formularul și vom captura rezultatul acestuia. Îl menținem simplu cu câmpuri de nume, e-mail și mesaje. Vom adăuga acțiunea de formular după ce am implementat arhitectura noastră fără server și am primit adresa URL, dar știm că va fi o solicitare POST, astfel încât să o putem adăuga. La sfârșitul formularului, adăugăm o etichetă de paragraf pentru afișare. mesaje de răspuns către utilizator, pe care le vom actualiza la apelarea trimisă.

<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>
Pentru a captura rezultatul, adăugăm un handler de trimitere la formular, transformăm parametrii formularului într-un obiect și trimitem JSON stringificat la funcția noastră Lambda. În funcția Lambda folosim JSON.parse()
pentru a citi datele noastre. Alternativ, puteți folosi jQuery Serialize sau query-string pentru a trimite și analiza parametrii formularului ca șir de interogare, dar JSON.stringify()
și JSON.parse()
sunt native.
(() => { 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)); }; })();
Continuați și trimiteți formularul, apoi capturați rezultatul consolei. Îl vom folosi în funcția noastră Lambda în continuare.

Invocarea funcțiilor Lambda
Mai ales în timpul dezvoltării, trebuie să testăm funcția noastră face ceea ce ne așteptăm. Cadrul Serverless oferă comanda invoke local
invoke
a declanșa funcția dvs. din mediile live și, respectiv, de dezvoltare . Ambele comenzi necesită trecerea numelui funcției, în cazul nostru staticSiteMailer
.
yarn sls invoke local --function staticSiteMailer
Pentru a transfera date simulate în funcția noastră, creați un fișier nou numit data.json
cu ieșirea din consolă capturată sub o cheie de body
dintr-un obiect JSON. Ar trebui să arate ceva de genul:
// data.json { "body": "{\"name\": \"Sender Name\",\"reply_to\": \"[email protected]\",\"message\": \"Sender message\"}" }
Pentru a invoca funcția cu datele locale, transmiteți argumentul --path
împreună cu calea către fișier.
yarn sls invoke local --function staticSiteMailer --path data.json

Veți vedea un răspuns similar cu cel dinainte, dar tasta de input
va conține evenimentul pe care l-am batjocorit. Să folosim datele noastre simulate pentru a trimite un e-mail folosind Serviciul de e-mail simplu!
Trimiterea unui e-mail cu serviciul de e-mail simplu
Vom înlocui funcția staticSiteMailer
cu un apel la o funcție privată sendEmail
. Deocamdată puteți comenta sau elimina codul șablonului și îl puteți înlocui cu:
// 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); } }); };
Mai întâi, analizăm event.body
pentru a captura datele formularului, apoi îl transmitem unei funcții private sendEmail
. sendEmail
este responsabil pentru trimiterea e-mailului, iar funcția de apel invers va returna un răspuns de eșec sau de succes cu err
sau data
. În cazul nostru, putem pur și simplu să înregistrăm eroarea sau datele, deoarece le vom înlocui cu apelul Lambda într-un moment.
Amazon oferă un SDK convenabil, aws-sdk
, pentru conectarea serviciilor lor cu funcțiile Lambda. Multe dintre serviciile lor, inclusiv SES, fac parte din aceasta. Îl adăugăm la proiect cu yarn add aws-sdk
și îl importăm în partea de sus a fișierului handler.
// handler.js const AWS = require('aws-sdk'); const SES = new AWS.SES();
În funcția noastră privată sendEmail
, construim parametrii SES.sendEmail
din datele din formularul analizat și folosim apelul invers pentru a returna un răspuns apelantului. Parametrii necesită următoarele ca obiect:
- Sursă
Adresa de e-mail SES o trimite de la . - Răspunde la adrese
O serie de adrese de e-mail adăugate la răspunsul la câmpul din e-mail. - Destinaţie
Un obiect care trebuie să conţină cel puţin o ToAddresses , CcAddresses sau BccAddresses . Fiecare câmp are o serie de adrese de e-mail care corespund câmpurilor la , cc și, respectiv, bcc . - Mesaj
Un obiect care conține Corpul și Subiectul .
Deoarece formData
este un obiect, putem apela câmpurile noastre de formular direct ca formData.message
, construim parametrii și trimitem. Vă transmitem e -mailul verificat SES către Source
și Destination.ToAddresses
. Atâta timp cât e-mailul este verificat, puteți transmite orice aici, inclusiv adrese de e-mail diferite. reply_to
, message
și name
obiectului nostru formData
pentru a completa câmpurile ReplyToAddresses
și Message.Body.Text.Data
.
// 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
va trimite e-mailul, iar apelul nostru va returna un răspuns. Invocarea funcției locale va trimite un e-mail la adresa dvs. verificată.
yarn sls invoke local --function staticSiteMailer --path data.json

SES.sendEmail
când reușește.Returnarea unui răspuns de la Handler
Funcția noastră trimite un e-mail folosind linia de comandă, dar nu așa vor interacționa utilizatorii noștri cu ea. Trebuie să returnăm un răspuns la trimiterea formularului nostru AJAX. Dacă nu reușește, ar trebui să returnăm un statusCode
corespunzător, precum și err.message
. Când reușește, 200
statusCode
este suficient, dar vom returna răspunsul mailului și în body. În staticSiteMailer
construim datele noastre de răspuns și înlocuim funcția de apel invers sendEmail
cu apel invers 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); }); };
Reapelul nostru Lambda returnează acum atât mesaje de succes, cât și mesaje de eșec de la SES.sendEmail
. Construim răspunsul cu verificări dacă există o err
, astfel încât răspunsul nostru să fie consecvent. Funcția de apel invers Lambda trece în sine null
în câmpul argumentului de eroare și răspunsul ca al doilea. Dorim să transmitem erori în continuare, dar dacă Lambda în sine eșuează, apelul său va fi apelat implicit cu răspunsul la eroare.
În headers
, va trebui să înlocuiți Access-Control-Allow-Origin
cu propriul domeniu. Acest lucru va împiedica orice alte domenii să vă folosească serviciul și, potențial, să acumulați o factură AWS în numele dvs.! Și nu o acopăr în acest articol, dar este posibil să configurați Lambda pentru a vă folosi propriul domeniu. Va trebui să aveți un certificat SSL/TLS încărcat pe Amazon. Echipa Serverless Framework a scris un tutorial fantastic despre cum să faceți acest lucru.
Invocarea funcției locale va trimite acum un e-mail și va returna răspunsul corespunzător.
yarn sls invoke local --function staticSiteMailer --path data.json

Apelarea funcției Lambda din formular
Serviciul nostru este complet! Pentru a-l implementa, rulați yarn sls deploy -v
. Odată implementat, veți obține o adresă URL care arată ceva de genul https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailer
pe care o puteți adăuga la acțiunea din formular. Apoi, creăm cererea AJAX și returnăm răspunsul utilizatorului.
(() => { 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); } }; }; })();
În apelarea AJAX, verificăm codul de stare cu response.target.status
. Dacă este altceva decât 200
, putem arăta utilizatorului un mesaj de eroare, în caz contrar anunță-i că mesajul a fost trimis. Deoarece Lambda returnează JSON stringificat, putem analiza corpul mesajului cu JSON.parse(response.target.response).message
. Este deosebit de util să înregistrați eroarea.
Ar trebui să puteți trimite formularul în întregime de pe site-ul dvs. static!

Pasii urmatori
Adăugarea unui formular de contact la statica este ușoară cu Serverless Framework și AWS. Există loc de îmbunătățire în codul nostru, cum ar fi adăugarea de validare a formularelor cu un honeypot, prevenirea apelurilor AJAX pentru formulare nevalide și îmbunătățirea UX în cazul răspunsului, dar acest lucru este suficient pentru a începe. Puteți vedea unele dintre aceste îmbunătățiri în depozitul static de e-mail pe care l-am creat. Sper că v-am inspirat să încercați singur Serverless!