بناء نموذج اتصال بدون خادم لموقعك الثابت
نشرت: 2022-03-10توفر مولدات المواقع الثابتة بديلاً سريعًا وبسيطًا لأنظمة إدارة المحتوى (CMS) مثل WordPress. لا يوجد إعداد للخادم أو قاعدة البيانات ، فقط عملية بناء و HTML و CSS وجافا سكريبت. لسوء الحظ ، بدون خادم ، من السهل تجاوز حدودهم بسرعة. على سبيل المثال ، في إضافة نموذج الاتصال.
مع ظهور بنية بدون خادم ، لا يلزم أن تكون إضافة نموذج اتصال إلى موقعك الثابت سببًا للتبديل إلى نظام إدارة المحتوى بعد الآن. من الممكن الحصول على أفضل ما في العالمين: موقع ثابت بنهاية خلفية بدون خادم لنموذج الاتصال (لا تحتاج إلى صيانته). ربما يكون أفضل ما في الأمر ، في المواقع ذات حركة المرور المنخفضة ، مثل المحافظ ، فإن الحدود العالية للعديد من المزودين الذين ليس لديهم خوادم تجعل هذه الخدمات مجانية تمامًا!
في هذه المقالة ، ستتعلم أساسيات Amazon Web Services (AWS) Lambda وواجهات برمجة تطبيقات خدمة البريد الإلكتروني البسيط (SES) لإنشاء رسالة بريدية خاصة بالموقع الثابت على Serverless Framework. ستتخذ الخدمة الكاملة بيانات النموذج المقدمة من طلب AJAX ، وتصل إلى نقطة نهاية Lambda ، وتقوم بتحليل البيانات لإنشاء معلمات SES ، وإرسال عنوان البريد الإلكتروني ، وإرجاع استجابة لمستخدمينا. سأوجهك خلال إعداد Serverless لأول مرة من خلال النشر. من المفترض أن يستغرق الأمر أقل من ساعة حتى تكتمل ، فلنبدأ!
اعداد
هناك حد أدنى من المتطلبات الأساسية لبدء استخدام تقنية Serverless. لأغراضنا ، إنها ببساطة Node Environment with 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 ، انقر على "المستخدمون" في الشريط الجانبي ، ثم زر "إضافة مستخدم".
- في صفحة إضافة مستخدم ، امنح المستخدم اسمًا - شيء مثل "بدون خادم" مناسب. حدد "الوصول الآلي" ضمن نوع الوصول ثم انقر فوق التالي.
- في شاشة الأذونات ، انقر فوق علامة التبويب "إرفاق السياسات الحالية مباشرةً" ، وابحث عن "وصول المسؤول" في القائمة ، وتحقق منه ، وانقر فوق التالي.
- في شاشة المراجعة ، يجب أن ترى اسم المستخدم الخاص بك ، مع "وصول برمجي" و "وصول المسؤول" ، ثم قم بإنشاء المستخدم.
- تعرض شاشة التأكيد للمستخدم "معرف مفتاح الوصول" و "مفتاح الوصول السري" ، وستحتاج إلى توفير الوصول إلى 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
ملفين: handler.js الذي يحتوي على وظيفة Lambda ، و serverless.yml وهو ملف التكوين للبنية الخالية من الخادم بالكامل. داخل ملف التكوين ، يمكنك تحديد العديد من المعالجات كما تريد ، وسيتم تعيين كل منها لوظيفة جديدة يمكنها التفاعل مع وظائف أخرى. في هذا المشروع ، سننشئ معالجًا واحدًا فقط ، ولكن في بنية كاملة بدون خادم ، سيكون لديك العديد من الوظائف المختلفة للخدمة.
في handler.js ، سترى دالة واحدة مُصدرة تسمى hello
. هذه هي الوظيفة الرئيسية (والوحيدة) حاليًا. تأخذ ، جنبًا إلى جنب مع جميع معالجات Node ، ثلاثة معلمات:
-
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's Serialize أو query-string لإرسال معلمات النموذج وتحليلها كسلسلة استعلام ولكن JSON.stringify()
و JSON.parse ( 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
لتمرير بيانات وهمية إلى وظيفتنا ، أنشئ ملفًا جديدًا باسم data.json
مع إخراج وحدة التحكم body
تحت مفتاح أساسي داخل كائن 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
سيحتوي على الحدث الذي سخرنا منه. دعنا نستخدم بياناتنا الوهمية لإرسال بريد إلكتروني باستخدام خدمة البريد الإلكتروني البسيطة!
إرسال بريد إلكتروني مع خدمة بريد إلكتروني بسيطة
سنقوم باستبدال وظيفة staticSiteMailer
وظيفة إرسال 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 في غضون لحظة.
توفر أمازون SDK مناسبًا ، aws-sdk
، لتوصيل خدماتها بوظائف Lambda. العديد من خدماتهم ، بما في ذلك SES ، جزء منه. نضيفه إلى المشروع مع yarn add aws-sdk
واستيراده إلى أعلى ملف المعالج.
// handler.js const AWS = require('aws-sdk'); const SES = new AWS.SES();
في وظيفة الإرسال الخاصة بنا ، SES.sendEmail
sendEmail
بيانات النموذج التي تم تحليلها ونستخدم رد الاتصال لإرجاع رد إلى المتصل. تتطلب المعلمات ما يلي ككائن:
- مصدر
عنوان البريد الإلكتروني الذي ترسله SES من . - الرد على العناوين
تمت إضافة مجموعة من عناوين البريد الإلكتروني إلى الرد على الحقل في البريد الإلكتروني. - المكان المقصود
كائن يجب أن يحتوي على واحد على الأقل ToAddresses أو CcAddresses أو BccAddresses . يأخذ كل حقل مجموعة من عناوين البريد الإلكتروني التي تتوافق مع الحقول to و cc و bcc على التوالي. - رسالة
كائن يحتوي على الجسم والموضوع .
نظرًا لأن formData
كائن يمكننا استدعاء حقول النموذج مباشرة مثل formData.message
، وبناء معلماتنا ، وإرسالها. نقوم بتمرير بريدك الإلكتروني الذي تم التحقق منه بواسطة SES إلى Source
Destination.ToAddresses
. طالما تم التحقق من البريد الإلكتروني ، يمكنك تمرير أي شيء هنا ، بما في ذلك عناوين البريد الإلكتروني المختلفة. قمنا reply_to
، message
، name
كائن formData
بنا لملء ReplyToAddresses
و 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
بإرسال البريد الإلكتروني وسيرجع رد الاتصال الخاص بنا ردًا. سيؤدي استدعاء الوظيفة المحلية إلى إرسال بريد إلكتروني إلى عنوانك الذي تم التحقق منه.
yarn sls invoke local --function staticSiteMailer --path data.json
إرجاع رد من المعالج
ترسل وظيفتنا بريدًا إلكترونيًا باستخدام سطر الأوامر ، ولكن هذه ليست الطريقة التي سيتفاعل بها المستخدمون معها. نحتاج إلى إعادة رد على إرسال نموذج AJAX الخاص بنا. في حالة فشلها ، يجب أن نعيد رمز الحالة المناسب بالإضافة إلى err.message
statusCode
عندما تنجح ، تكون 200
statusCode
كافية ، لكننا سنعيد استجابة الإرسال في النص أيضًا. في 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 لاستخدام المجال الخاص بك. ستحتاج إلى تحميل شهادة SSL / TLS على أمازون. كتب فريق Serverless Framework برنامجًا تعليميًا رائعًا حول كيفية القيام بذلك.
سيؤدي استدعاء الوظيفة المحلية الآن إلى إرسال بريد إلكتروني وإرجاع الرد المناسب.
yarn sls invoke local --function staticSiteMailer --path data.json
استدعاء دالة لامدا من النموذج
خدمتنا كاملة! لنشره ، قم بتشغيل yarn sls deploy -v
. بمجرد نشره ، ستحصل على عنوان URL يشبه https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailer
والذي يمكنك إضافته إلى إجراء النموذج. بعد ذلك ، نقوم بإنشاء طلب 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 للنماذج غير الصالحة وتحسين تجربة المستخدم إذا كانت الاستجابة ، ولكن هذا يكفي للبدء. يمكنك رؤية بعض هذه التحسينات في موقع إعادة إرسال البريد الثابت الذي قمت بإنشائه. آمل أن أكون قد ألهمتك لتجربة Serverless بنفسك!