Membangun Formulir Kontak Tanpa Server Untuk Situs Statis Anda
Diterbitkan: 2022-03-10Generator situs statis menyediakan alternatif yang cepat dan sederhana untuk Sistem Manajemen Konten (CMS) seperti WordPress. Tidak ada penyiapan server atau basis data, hanya proses pembuatan dan HTML, CSS, dan JavaScript sederhana. Sayangnya, tanpa server, mudah untuk mencapai batasnya dengan cepat. Misalnya, dalam menambahkan formulir kontak.
Dengan munculnya arsitektur tanpa server menambahkan formulir kontak ke situs statis Anda tidak perlu menjadi alasan untuk beralih ke CMS lagi. Dimungkinkan untuk mendapatkan yang terbaik dari kedua dunia: situs statis dengan back-end tanpa server untuk formulir kontak (yang tidak perlu Anda pertahankan). Mungkin yang terbaik dari semuanya, di situs dengan lalu lintas rendah, seperti portofolio, batas tinggi dari banyak penyedia tanpa server membuat layanan ini sepenuhnya gratis!
Dalam artikel ini, Anda akan mempelajari dasar-dasar Amazon Web Services (AWS) Lambda dan Simple Email Service (SES) API untuk membangun mailer situs statis Anda sendiri di Serverless Framework. Layanan lengkap akan mengambil data formulir yang dikirimkan dari permintaan AJAX, mencapai titik akhir Lambda, mengurai data untuk membangun parameter SES, mengirim alamat email, dan mengembalikan respons untuk pengguna kami. Saya akan memandu Anda melalui penyiapan Tanpa Server untuk pertama kalinya melalui penerapan. Perlu waktu kurang dari satu jam untuk menyelesaikannya, jadi mari kita mulai!

Pengaturan
Ada prasyarat minimal untuk memulai dengan teknologi Tanpa Server. Untuk tujuan kami, ini hanyalah Lingkungan Node dengan Benang, Kerangka Tanpa Server, dan akun AWS.
Menyiapkan Proyek

Kami menggunakan Yarn untuk menginstal Kerangka Tanpa Server ke direktori lokal.
- Buat direktori baru untuk meng-host proyek.
- Arahkan ke direktori di antarmuka baris perintah Anda.
- Jalankan
yarn init
untuk membuat filepackage.json
untuk proyek ini. - Jalankan
yarn add serverless
untuk menginstal framework secara lokal. - Jalankan
yarn serverless create --template aws-nodejs --name static-site-mailer
untuk membuat template layanan Node dan beri namastatic-site-mailer
.
Proyek kami telah disiapkan tetapi kami tidak akan dapat melakukan apa pun sampai kami menyiapkan layanan AWS kami.
Menyiapkan Akun Layanan Web Amazon, Kredensial, dan Layanan Email Sederhana

Kerangka Tanpa Server telah merekam panduan video untuk menyiapkan kredensial AWS, tetapi saya juga telah mencantumkan langkah-langkahnya di sini.
- Mendaftar untuk akun AWS atau masuk jika Anda sudah memilikinya.
- Di bilah pencarian AWS, cari "IAM".
- Di halaman IAM, klik "Pengguna" di bilah sisi, lalu tombol "Tambah pengguna".
- Pada halaman Tambahkan pengguna, beri nama pengguna – sesuatu seperti “tanpa server” sesuai. Centang "Akses terprogram" di bawah Jenis akses lalu klik berikutnya.
- Pada layar izin, klik tab “Lampirkan kebijakan yang ada secara langsung”, cari “AdministratorAccess” dalam daftar, centang, dan klik berikutnya.
- Pada layar tinjauan Anda akan melihat nama pengguna Anda, dengan "Akses program", dan "AdministratorAccess", lalu buat pengguna.
- Layar konfirmasi menunjukkan kepada pengguna “Access key ID” dan “Secret access key”, Anda akan memerlukan ini untuk menyediakan akses ke Serverless Framework. Di CLI Anda, ketikkan
yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEY
, gantiYOUR_ACCESS_KEY_ID
danYOUR_SECRET_ACCESS_KEY
dengan kunci pada layar konfirmasi.
Kredensial Anda telah dikonfigurasi sekarang, tetapi saat kita berada di konsol AWS, mari siapkan Layanan Email Sederhana.
- Klik Beranda Konsol di pojok kiri atas untuk pulang.
- Di halaman beranda, di bilah pencarian AWS, cari "Layanan Email Sederhana".
- Di halaman Beranda SES, klik "Alamat Email" di bilah sisi.
- Pada halaman daftar Alamat Email, klik tombol “Verifikasi Alamat Email Baru”.
- Di jendela dialog, ketik alamat email Anda lalu klik "Verifikasi Alamat Email Ini".
- Anda akan menerima email dalam beberapa saat yang berisi tautan untuk memverifikasi alamat. Klik tautan untuk menyelesaikan proses.
Sekarang setelah akun kita dibuat, mari kita intip file template Serverless.
Menyiapkan Kerangka Tanpa Server
Menjalankan serverless create
dua file: handler.js yang berisi fungsi Lambda, dan serverless.yml yang merupakan file konfigurasi untuk seluruh Arsitektur Tanpa Server. Di dalam file konfigurasi, Anda dapat menentukan penangan sebanyak yang Anda inginkan, dan masing-masing akan dipetakan ke fungsi baru yang dapat berinteraksi dengan fungsi lain. Dalam proyek ini, kami hanya akan membuat satu handler, tetapi dalam Arsitektur Tanpa Server penuh, Anda akan memiliki beberapa dari berbagai fungsi layanan.

Di handler.js, Anda akan melihat satu fungsi yang diekspor bernama hello
. Ini adalah fungsi utama (dan satu-satunya) saat ini. Ini, bersama dengan semua penangan Node, mengambil tiga parameter:
-
event
Ini dapat dianggap sebagai data input untuk fungsi tersebut. -
context object
Ini berisi informasi runtime dari fungsi Lambda. -
callback
Parameter opsional untuk mengembalikan informasi ke pemanggil.
// 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); };
Di bagian bawah hello
, ada panggilan balik. Ini adalah argumen opsional untuk mengembalikan respons, tetapi jika tidak dipanggil secara eksplisit , itu akan secara implisit kembali dengan null
. Panggilan balik membutuhkan dua parameter:
- kesalahan kesalahan
Untuk memberikan informasi kesalahan ketika Lambda itu sendiri gagal. Ketika Lambda berhasil,null
harus diteruskan ke parameter ini. - Hasil objek
Untuk menyediakan objek respons. Itu harus kompatibel denganJSON.stringify
. Jika ada parameter di bidang kesalahan, bidang ini diabaikan.
Situs statis kami akan mengirimkan data formulir kami di badan acara dan panggilan balik akan mengembalikan respons untuk dilihat pengguna kami.
Di serverless.yml Anda akan melihat nama layanan, informasi penyedia, dan fungsinya.
# serverless.yml service: static-site-mailer provider: name: aws runtime: nodejs6.10 functions: hello: handler: handler.hello

Perhatikan pemetaan antara fungsi hello dan handler? Kami dapat memberi nama file dan fungsi kami apa saja dan selama itu memetakan ke konfigurasi itu akan berfungsi. Mari kita ganti nama fungsi kita menjadi staticSiteMailer
.
# serverless.yml functions: staticSiteMailer: handler: handler.staticSiteMailer
// handler.js module.exports.staticSiteMailer = (event, context, callback) => { ... };
Fungsi Lambda memerlukan izin untuk berinteraksi dengan infrastruktur AWS lainnya. Sebelum kami dapat mengirim email, kami harus mengizinkan SES untuk melakukannya. Di serverless.yml, di bawah provider.iamRoleStatements
tambahkan izin.
# serverless.yml provider: name: aws runtime: nodejs6.10 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: ["*"]
Karena kita memerlukan URL untuk tindakan formulir kita, kita perlu menambahkan peristiwa HTTP ke fungsi kita. Di serverless.yml kami membuat jalur, menentukan metode sebagai post
, dan menyetel CORS ke true untuk keamanan.
functions: staticSiteMailer: handler: handler.staticSiteMailer events: - http: method: post path: static-site-mailer cors: true
File serverless.yml dan handler.js kami yang diperbarui akan terlihat seperti:
# 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); };
Arsitektur Tanpa Server kami telah disiapkan, jadi mari kita terapkan dan ujilah. Anda akan mendapatkan respons JSON sederhana.
yarn sls deploy --verbose yarn sls invoke --function staticSiteMailer { "statusCode": 200, "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}" }

Membuat Formulir HTML
Input fungsi Lambda dan output formulir harus cocok, jadi sebelum kita membangun fungsi, kita akan membuat formulir dan menangkap outputnya. Kami membuatnya sederhana dengan bidang nama, email, dan pesan. Kami akan menambahkan tindakan formulir setelah kami menerapkan arsitektur tanpa server kami dan mendapatkan URL kami, tetapi kami tahu itu akan menjadi permintaan POST sehingga kami dapat menambahkannya. Di akhir formulir, kami menambahkan tag paragraf untuk ditampilkan pesan tanggapan kepada pengguna yang akan kami perbarui pada panggilan balik pengiriman.

<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>
Untuk menangkap output, kami menambahkan penangan pengiriman ke formulir, mengubah parameter formulir kami menjadi objek, dan mengirim JSON string ke fungsi Lambda kami. Dalam fungsi Lambda kami menggunakan JSON.parse()
untuk membaca data kami. Atau, Anda bisa menggunakan jQuery's Serialize atau query-string untuk mengirim dan mengurai parameter formulir sebagai string kueri tetapi JSON.stringify()
dan JSON.parse()
adalah asli.
(() => { 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)); }; })();
Silakan dan kirimkan formulir Anda lalu ambil output konsol. Kami akan menggunakannya dalam fungsi Lambda kami selanjutnya.

Menjalankan Fungsi Lambda
Terutama selama pengembangan, kita perlu menguji fungsi kita melakukan apa yang kita harapkan. Kerangka Tanpa Server menyediakan perintah invoke local
invoke
memicu fungsi Anda masing-masing dari lingkungan langsung dan pengembangan . Kedua perintah memerlukan nama fungsi yang dilewati, dalam kasus kami staticSiteMailer
.
yarn sls invoke local --function staticSiteMailer
Untuk meneruskan data tiruan ke dalam fungsi kita, buat file baru bernama data.json
dengan output konsol yang ditangkap di bawah kunci body
di dalam objek JSON. Seharusnya terlihat seperti:
// data.json { "body": "{\"name\": \"Sender Name\",\"reply_to\": \"[email protected]\",\"message\": \"Sender message\"}" }
Untuk memanggil fungsi dengan data lokal, berikan argumen --path
bersama dengan path ke file.
yarn sls invoke local --function staticSiteMailer --path data.json

Anda akan melihat respons yang serupa dengan sebelumnya, tetapi kunci input
akan berisi acara yang kami olok-olok. Mari gunakan data tiruan kami untuk mengirim email menggunakan Layanan Email Sederhana!
Mengirim Email Dengan Layanan Email Sederhana
Kita akan mengganti fungsi staticSiteMailer
dengan panggilan ke fungsi private sendEmail
. Untuk saat ini Anda dapat mengomentari atau menghapus kode template dan menggantinya dengan:
// 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); } }); };
Pertama, kami mengurai event.body
untuk menangkap data formulir, lalu kami meneruskannya ke fungsi sendEmail
pribadi. sendEmail
bertanggung jawab untuk mengirim email, dan fungsi panggilan balik akan mengembalikan respons yang gagal atau berhasil dengan err
atau data
. Dalam kasus kami, kami dapat dengan mudah mencatat kesalahan atau data karena kami akan segera menggantinya dengan panggilan balik Lambda.
Amazon menyediakan SDK yang nyaman, aws-sdk
, untuk menghubungkan layanan mereka dengan fungsi Lambda. Banyak dari layanan mereka, termasuk SES, adalah bagian darinya. Kami menambahkannya ke proyek dengan yarn add aws-sdk
dan mengimpornya ke bagian atas file handler.
// handler.js const AWS = require('aws-sdk'); const SES = new AWS.SES();
Dalam fungsi sendEmail
pribadi kami, kami membangun parameter SES.sendEmail
dari data formulir yang diuraikan dan menggunakan panggilan balik untuk mengembalikan respons ke pemanggil. Parameter memerlukan yang berikut ini sebagai objek:
- Sumber
Alamat email yang dikirim SES dari . - BalasKeAlamat
Array alamat email ditambahkan ke balasan ke bidang di email. - Tujuan
Objek yang harus berisi setidaknya satu ToAddresses , CcAddresses , atau BccAddresses . Setiap bidang mengambil larik alamat email yang sesuai dengan bidang ke , cc , dan bcc masing-masing. - Pesan
Sebuah objek yang berisi Tubuh dan Subjek .
Karena formData
adalah objek, kami dapat memanggil bidang formulir kami secara langsung seperti formData.message
, membangun parameter kami, dan mengirimkannya. Kami meneruskan email terverifikasi SES Anda ke Source
and Destination.ToAddresses
. Selama email diverifikasi, Anda dapat meneruskan apa pun di sini, termasuk alamat email yang berbeda. Kami mencabut reply_to
, message
, dan name
dari objek formData
kami untuk mengisi bidang ReplyToAddresses
dan 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
akan mengirimkan email tersebut dan callback kami akan membalasnya. Memanggil fungsi lokal akan mengirim email ke alamat terverifikasi Anda.
yarn sls invoke local --function staticSiteMailer --path data.json

SES.sendEmail
ketika berhasil.Mengembalikan Tanggapan Dari Handler
Fungsi kami mengirim email menggunakan baris perintah, tapi bukan itu cara pengguna kami berinteraksi dengannya. Kami perlu mengembalikan tanggapan atas pengiriman formulir AJAX kami. Jika gagal, kita harus mengembalikan statusCode
yang sesuai serta err.message
. Ketika berhasil, 200
statusCode
sudah cukup, tetapi kami juga akan mengembalikan respons mailer di badan. Di staticSiteMailer
kami membangun data respons kami dan mengganti fungsi panggilan balik sendEmail
kami dengan panggilan balik 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); }); };
Callback Lambda kami sekarang mengembalikan pesan sukses dan gagal dari SES.sendEmail
. Kami membangun respons dengan memeriksa apakah ada err
sehingga respons kami konsisten. Fungsi panggilan balik Lambda itu sendiri melewati null
di bidang argumen kesalahan dan respons sebagai yang kedua. Kami ingin meneruskan kesalahan, tetapi jika Lambda itu sendiri gagal, panggilan baliknya akan dipanggil secara implisit dengan respons kesalahan.
Di headers
, Anda harus mengganti Access-Control-Allow-Origin
dengan domain Anda sendiri. Ini akan mencegah domain lain menggunakan layanan Anda dan berpotensi membebani tagihan AWS atas nama Anda! Dan saya tidak membahasnya dalam artikel ini, tetapi dimungkinkan untuk menyiapkan Lambda untuk menggunakan domain Anda sendiri. Anda harus memiliki sertifikat SSL/TLS yang diunggah ke Amazon. Tim Serverless Framework menulis tutorial fantastis tentang cara melakukannya.
Memanggil fungsi lokal sekarang akan mengirim email dan mengembalikan respons yang sesuai.
yarn sls invoke local --function staticSiteMailer --path data.json

Memanggil Fungsi Lambda Dari Formulir
Layanan kami selesai! Untuk menyebarkannya, jalankan yarn sls deploy -v
. Setelah diterapkan, Anda akan mendapatkan URL yang terlihat seperti https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailer
yang dapat Anda tambahkan ke tindakan formulir. Selanjutnya, kami membuat permintaan AJAX dan mengembalikan respons ke pengguna.
(() => { 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); } }; }; })();
Dalam panggilan balik AJAX, kami memeriksa kode status dengan response.target.status
. Jika itu selain 200
, kami dapat menampilkan pesan kesalahan kepada pengguna, jika tidak, beri tahu mereka bahwa pesan telah dikirim. Karena Lambda kami mengembalikan string JSON, kami dapat mengurai pesan isi dengan JSON.parse(response.target.response).message
. Ini sangat berguna untuk mencatat kesalahan.
Anda harus dapat mengirimkan formulir Anda sepenuhnya dari situs statis Anda!

Langkah selanjutnya
Menambahkan formulir kontak ke statis Anda mudah dilakukan dengan Serverless Framework dan AWS. Ada ruang untuk perbaikan dalam kode kami, seperti menambahkan validasi formulir dengan honeypot, mencegah panggilan AJAX untuk formulir yang tidak valid dan meningkatkan UX jika respons, tetapi ini cukup untuk memulai. Anda dapat melihat beberapa peningkatan ini dalam repo mailer situs statis yang saya buat. Saya harap saya telah menginspirasi Anda untuk mencoba sendiri Tanpa Server!