Обработка форм для сайтов Jamstack с помощью Cloudflare Workers

форм для сайтов Jamstack Изучение

В этом руководстве вы узнаете, как создать службу обработки форм для вашего веб-сайта Jamstack или одностраничного приложения (SPA) с помощью Cloudlflare Workers.

Благодаря технологии Jamstack HTML-код обрабатывается во время сборки, а затем развертывается на пограничных серверах. Это позволяет конечным пользователям очень быстро загружаться. Кроме того, компании выигрывают, платя значительно меньшую плату за хостинг.

Одна из проблем с технологией Jamstack заключается в том, как работать с функциями сайта, которые могут быть реализованы только с помощью серверных технологий. Например, обработка форм относительно проста, если у вас есть доступ к серверной технологии, такой как PHP, которую вы можете просто использовать mail(, , )для сбора и отправки почтовых данных.

Конечно, сайты Jamstack не остались без внимания. Вы можете запускать серверные приложения на сайте Jamstack, используя бессерверные вычисления. Но вам нужно будет внедрить микросервисную архитектуру в свою внутреннюю разработку. Бессерверные вычисления требуют, чтобы вы встраивали свою логику в слабо связанные, независимо развертываемые службы.

Бессерверные вычисления могут быть намного более рентабельными, чем аренда частных серверов, часто необходимых для работы серверных приложений. Дополнительным преимуществом бессерверных вычислений является то, что вы можете начать создавать более сложные рабочие процессы, используя дополнительные службы (например, использование таких служб, как Airtable, для хранения данных форм).

В этом руководстве вы узнаете, как создать и развернуть службу обработки форм для интерфейсного SPA React. Технически подойдет любой интерфейсный фреймворк. Мы будем использовать Cloudflare Workers для разработки нашей бессерверной функции. Прежде чем мы начнем работать над кодом, давайте сначала рассмотрим, почему мы будем использовать этот технологический стек. (Если вы хотите сразу перейти к практической части, перейдите в раздел проекта.)

О сторонних службах обработки форм

Уже существует большое количество сервисов обработки форм API, которые предоставляют необходимые нам функции. Это включает:

  • FormSpree
  • Getform
  • FormData
  • Формы Netlify

Они предлагают следующие функции:

  • Уведомление по электронной почте
  • блокировка спама
  • интеграция с другими сервисами через Zapier
  • просмотр данных приборной панели
  • загрузка и хранение файлов
  • CSV экспорт

Это большая ценность, которая избавляет вас от необходимости создавать такую ​​услугу самостоятельно. Кроме того, интеграция службы с существующим веб-приложением занимает не более пяти минут. Большинство платформ предлагают бесплатный план, который дает вам от 50 до 100 бесплатных материалов в месяц с примерно 100 МБ хранилища файлов.

Платные планы начинаются от 9 долларов в месяц с 1000 отправлений и 1 ГБ хранилища для загрузки файлов. Если вы используете эту услугу для сбора потенциальных клиентов, цена вполне приемлемая. Однако, если вы используете его для другой цели — например, для сбора больших объемов полевых данных — он может быстро стать дорогостоящим.

Именно здесь может оказаться полезным создание собственной службы обработки форм. Есть несколько преимуществ, в том числе:

  • более низкая стоимость отправки формы
  • реализация настраиваемых политик безопасности
  • неограниченная интеграция с другими сервисами
  • сокращение задержки, так как вы контролируете, как и где размещается сервис
  • возможность добавлять новые функции, которые в настоящее время не предлагаются провайдером обработки форм

Что касается низкой стоимости на представления, поставщики транзакций службы электронной почты, такие как SendGrid и Mailgun в настоящее время есть предложение, что позволяет передавать между 3000 до 5000 писем в месяц бесплатно. Предложение первого постоянно бесплатное, а предложение второго длится всего три месяца.

Это, конечно, уже слишком много электронной почты для чьего-либо почтового ящика. Вероятно, вы захотите отправить данные формы прямо в свою базу данных или в службу приложения, предназначенную для обработки этих данных. В этом случае вы, вероятно, заплатите менее 10 долларов за миллион представленных материалов.

Эти цены, которые я оценил, основаны на комбинированных средних ценах на основные предложения по бессерверным вычислениям и бессерверным базам данных. Если вам нужно файловое хранилище, вы можете получить 250 гигабайт объектного хранилища Linode за 5 долларов в месяц. На самом деле вы получите гораздо больше пользы, если потратите время на создание сервиса самостоятельно.

Надеюсь, причин достаточно. Если нет, научитесь строить просто для удовольствия. Вы можете применить полученные знания в других сферах. В следующем разделе мы рассмотрим, почему мы решили создать собственный сервис с Cloudflare Workers.

О Cloudflare Workers

Первой представленной платформой для бессерверных вычислений был Google App Engine, запущенный в 2008 году. Однако первым коммерчески успешным бессерверным предложением стала AWS Lambda, представленная Amazon в 2014 году. Позже, в 2016 году, Google представила второе бессерверное предложение. известный как Google Cloud Functions. Вскоре последовали IBM Cloud Functions и Azure Functions.

Хотя все эти службы предоставляют преимущества выполнения внутреннего кода при значительно меньшей стоимости, большинство из них страдают от проблемы, известной как » холодный старт«. Здесь неактивному контейнеру, в котором размещена ваша функция, требуется от 1 до 10+ секунд, чтобы ответить на запрос. Существует множество задокументированных обходных путей, призванных улучшить ситуацию, но не решить ее полностью.

Cloudflare Workers — это последняя разработка на рынке бессерверных вычислений. Компания решила проблему холодного запуска, при которой для простаивающих бессерверных функций время загрузки составляет 0 миллисекунд для ответа на запросы. Они достигли этого, используя среду выполнения V8 для выполнения бессерверных функций вместо их запуска в среде Node.js. Это руководство объясняет, как это работает.

Конец формы

Кроме того, Cloudflare — это платформа для пограничных вычислений. Это в основном означает, что код выполняется на серверах, ближайших к конечным пользователям. Это еще больше сокращает сетевую задержку и делает ответ вашего приложения мгновенным.

Надеюсь, теперь я убедил вас, что Cloudlflare Workers — это правильный путь. Итак, приступим к строительству.

О проекте

Исходный код завершенных проектов можно найти по следующим ссылкам:

  • Пользовательский интерфейс формы Cloudflare: одностраничное приложение React
  • Сервис форм Cloudflare: приложение Cloudflare Workers

В этом руководстве мы шаг за шагом рассмотрим создание приложения Workers. Затем мы загрузим и настроим завершенный SPA (ссылка выше) для подключения к нашему завершенному проекту Workers.

Мы не будем создавать пользовательский интерфейс. Мы развернем приложение и протестируем его с приложением Workers, которое мы собираемся построить. В следующем разделе описаны все предварительные условия, необходимые для работы с руководством.

Предпосылки

Это руководство предназначено для разработчиков Node.js среднего и продвинутого уровней. Я предполагаю, что вы знакомы с нотацией ES6 + и REST API. В вашей среде разработки вам понадобится следующая настройка:

  • Node.js
  • Код Visual Studio
  • расширение VS Code REST Client

Расширение REST Client — более удобный инструмент для тестирования интерфейсов REST, чем использование внешних приложений.

Настройка учетных записей

В этом разделе мы настроим все учетные записи служб, которые нам понадобятся для создания нашего рабочего для обработки электронной почты. Обратите внимание на все токены API и другие идентификаторы, которые мы будем использовать позже в процессе разработки.

1. Пользовательский домен

Чтобы следовать этому руководству, настоятельно рекомендуется иметь доступ к личному домену и адресу электронной почты, использующему этот домен. Однако вы можете заставить код работать, используя домен песочницы и бесплатный поддомен, который Cloudflare предоставляет вам при регистрации. Обратите внимание, что при настройке личного домена на Mailgun требуется информация о кредитной карте.

Наличие личного домена позволит вам:

  • разверните свои проекты Cloudflare в личном домене
  • получить доступ к вашим развернутым журналам Workers в режиме реального времени
  • отправлять подлинные электронные письма, которые не попадут в ящик для спама

Если у вас нет доступа к личному домену, я настоятельно рекомендую вам приобрести новый домен в FastComet. Я рекомендую их по той причине, что они предоставят вам бесплатный пакет Lite Email, который вы можете использовать для настройки адреса электронной почты личного домена. Большинство провайдеров взимают дополнительную плату за хостинг электронной почты.

В следующем разделе мы создадим учетную запись Mailgun.

2. Настройка Mailgun

Mailgun — это служба API электронной почты, которая позволяет разработчикам интегрировать функции электронной почты в свои приложения через API. Мы будем использовать их интерфейс REST API для отправки и электронной почты из нашего приложения Workers получателю. В основном это означает, что нам нужно только использовать Fetchили Axiosотправить электронное письмо. Используйте следующее руководство для настройки учетной записи Mailgun:

  1. Зайдем к знаку вверхстраницы и создать новую учетную запись, используя свободный план.
  2. Подтвердите свою учетную запись, используя адрес электронной почты и SMS-код, отправленный на ваш телефон.
  3. На панели инструментов Mailgun перейдите в раздел «Отправка»> » Домены«, и вы обнаружите, что домен песочницы был создан для вас. Это бесплатный домен, предназначенный для проверки отправки электронных писем.
  4. В домене песочницы вам разрешено отправлять электронное письмо только авторизованному получателю. На правой боковой панели текущей панели инструментов вы найдете форму, в которой вы можете указать адрес электронной почты получателя. Добавьте сейчас. Это будет адрес электронной почты, на который будут приходить электронные письма, отправленные из приложения Workers, которое мы будем создавать.
  5. Электронное письмо будет отправлено в почтовый ящик авторизованного получателя. Нажмите «Подтвердить», чтобы завершить шаг 4.
  6. На странице » Обзор»песочницы нажмите » API» > » Выбрать«.
  7. Далее выберите вкладку завиток. Обратите внимание на ваш API Keyи API base URL.
  8. Отправьте тестовое электронное письмо с помощью команды cURL, предоставленной для изолированного домена. Убедитесь, что вы заменили соответствующие поля своими токенами API и авторизованным получателем электронной почты.

Отправьте тестовое электронное письмо с помощью команды cURL

Вот краткий пример того, как вы можете отправить свое:

curl -s --user 'api:key-0303d350c68aa534560ed0838bca66e' \
  https://api.mailgun.net/v3/sandbox9cfff108345efd4a15fd76.mailgun.org/messages \
  -F from='John Doe <john.doe@gmail.com>' \
  -F to=jane.doe@gmail.com \
  -F subject='Hello' \
  -F text='Message sent using Mailgun service'

В случае успеха вы должны получить результат, подобный показанному ниже:

{
  "id": "<20210406124818.1.7CAD4673034EEB0E@sandbox9cfff108345efd4a15fd76.mailgun.org>",
  "message": "Queued. Thank you."
}

Вы также должны получить электронное письмо либо в почтовый ящик авторизованного получателя, либо в ящик для спама. Если это произойдет, вы успешно настроили свою учетную запись Mailgun.

Если вы хотите использовать собственный домен в качестве домена отправки, обратите внимание, что требуется информация о кредитной карте. Вы можете следовать приведенным здесь инструкциям, чтобы узнать, как его настроить. Использование личного домена позволяет вам разблокировать лимиты на отправку, а также проверить ваш источник электронной почты, чтобы они всегда попадали в почтовый ящик пользователей, а не в ящик для спама.

В конце этого раздела у вас должен быть доступ к следующему:

  • КЛЮЧ API: например,api:key-0303d350c68aa534560ed0838bca66e
  • URL-адрес API BASE: например,https://api.mailgun.net/v3/sandbox9cfff108345efd4a15fd76.mailgun.org
  • a FROM_EMAIL_ADDRESS: используйте любой адрес Gmail или адрес личного домена, который вы зарегистрировали в Mailgun.
  • TO_EMAIL_ADDRESS: авторизованный получатель

Обратите внимание, что ключ API также находится в разделе » Настройки» > » Ключи API» > » Закрытый ключ API«.

3. Настройка Cloudflare Workers

Для начала просто зарегистрируйте учетную запись Cloudflare Workers. Следуйте предоставленным инструкциям:

  1. введите адрес электронной почты и пароль
  2. выберите поддомен для своей учетной записи
  3. выберите тариф: выберите бесплатно
  4. проверьте свой адрес электронной почты

Затем установите и настройте Wrangler CLI, который вы будете использовать для разработки проектов Workers:

# Install wrangler CLI globally
npm install -g @cloudflare/wrangler

# Confirm version
wrangler --version

# Login to your Workers account
wrangler login

# Confirm login status
wrangler whoami

Если вам не удается выполнить команду входа в систему, существует несколько способов решения этой проблемы с GitHub. Вот шаги, которые сработали на моей машине:

  1. Выполните wrangler loginснова в терминале.
  2. Как только страница авторизации загрузится, нажмите F12, чтобы открыть Inspector, затем переключите его на вкладку Network.
  3. Нажмите на Authorize Wranglerкнопку и подождите, пока не появится сообщение «Wrangler теперь авторизован».
  4. На вкладке Network в консоли Inspector найдите последний запрос POST. Щелкните по нему, чтобы выделить его.
  5. Должна появиться вкладка «Запрос». Щелкните по нему, чтобы получить к нему доступ. Должны быть данные JSON. Свойство «ключ» — это токен API. Скопируйте это. Должна появиться вкладка «Запрос»
  6. Вернитесь в терминал и нажмите ctrl+, cчтобы отменить последнюю команду. Выполните команду wrangler config. Вам будет предложено ввести свой токен API. Вставьте только что скопированный ключ и нажмите enter. Он должен вернуть сообщение «Успешно настроено».
  7. Подтвердите, что аутентификация прошла успешно, выполнив wrangler whoami.
Читайте также:  Перенаправление ввода-вывода в Ubuntu

В следующем подразделе мы рассмотрим, как добавить собственный домен в вашу учетную запись Cloudflare. Если у вас его нет, просто перейдите к разделу » Разработка проекта «, где мы сможем продолжить без него.

Настройка пользовательского домена на Cloudflare

Если у вас есть собственный домен, вы сможете в реальном времени получать доступ к журналам вашего приложения Workers. Чтобы настроить его, просто следуйте этим инструкциям:

1. Добавьте свой сайт (собственный домен) в Cloudflare: инструкции здесь

2. Измените серверы доменных имен на Cloudflare: инструкции здесь.

Добавление личного домена в Cloudflare также позволит вам опубликовать приложение Workers в личном домене. Мы увидим, как это сделать, в следующем разделе. Обратите внимание, что смена серверов домена вступает в силу в течение минуты, хотя вам будет сообщено, что это займет 24 часа. Вы можете подтвердить статус с помощью глобальной проверки DNS. Добавление личного домена в Cloudflare также

3. Загрузите двоичный файл Cloudflared: ссылки для скачивания здесь. Извлеките двоичный файл и поместите его в $PATHпеременную среды.

4. Аутентифицировать команду Cloudflared: инструкциипо использованию cloudflared tunnel loginкоманды.

После завершения вышеуказанной настройки вы сможете запустить команду wrangler tailдля потоковой передачи опубликованных журналов приложений Workers в режиме реального времени.

Разработка проекта

В этом разделе мы выполним собственно кодирование. У вас должны быть следующие токены и идентификаторы:

  • КЛЮЧ API MAILGUN
  • БАЗОВЫЙ URL MAILGUN API
  • С АДРЕСА ЭЛЕКТРОННОЙ ПОЧТЫ
  • НА АДРЕС ЭЛЕКТРОННОЙ ПОЧТЫ
  • Идентификатор учетной записи Cloudflare
  • Идентификатор зоны Cloudflare (доступен на панели управления персонального домена в Cloudflare)

1. Создать проект

На этом этапе мы создадим наш проект Workers. Просто выполните следующие команды в терминале:

# Scaffold your Workers project
wrangler generate cloudflare-form-service

# Install package dependencies
cd cloudflare-form-service
npm install

# Open in VS Code
code .

Затем обновите wrangler.tomlи предоставьте account_id:

name = "cloudflare-form-service"
type = "javascript"
account_id = "<place your account id here></place>"
workers_dev = true
route = ""
zone_id = ""

После сохранения изменений откройте package.jsonи перезапишите scriptsраздел следующим образом:

{
  "scripts": {
    "dev": "wrangler dev",
    "preview": "wrangler preview",
    "format": "prettier --write \"**/*.{js,css,json,md}\""
  },
}

Удобно установить эти команды здесь, чтобы вы могли легко запускать их в VS Code. Вы можете запустить devкоманду или просто выполнить ее npm run devв своем терминале. Это должно запустить сервер разработки, что займет несколько секунд.

Создайте файл test.httpи вставьте следующие команды:

# Test GET request
GET http://localhost:8787/ HTTP/1.1

###

После сохранения в test.httpфайле должна появиться интерактивная ссылка «Отправить запрос» прямо над командой GET. Эта функция поддерживается расширением REST Client. Щелкните по нему, чтобы запустить запрос. Должна открыться новая вкладка, отображающая ответ. Обратите внимание на время в обе стороны, отображаемое в заголовке вкладки.

После сохранения в test

На следующем шаге мы начнем писать код для обработки запросов POST.

2. Обработка запросов POST

Давайте посмотрим на наш текущий код Workers. Открыто index.js:

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})
/**
 * Respond with hello worker text
 * @param {Request} request
 */
async function handleRequest(request) {
  return new Response('Hello worker!', {
    headers: { 'content-type': 'text/plain' },
  })
}

В настоящее время наше приложение Workers прослушивает любой тип запроса и передает его обработчику ответа, который возвращает текстовое сообщение «Hello worker!»

Внесем следующие изменения:

  1. определить конкретный обработчик ответа для запросов POST
  2. определить функцию для преобразования данных формы в объект JavaScript
  3. заблокировать все другие типы запросов, вернув сообщение 404

Замените текущий index.jsсо следующими изменениями:

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  if (request.method === 'POST') {
    return handlePostRequest(request)
  } else {
    return new Response('Object Not Found', {
      statusText: 'Object Not Found',
      status: 404,
    })
  }
}


/**
 * Return body data in JSON format
 * @param {Request} request
 */
async function readRequestBody(request) {
  const { headers } = request
  const contentType = headers.get('content-type')
  if (!contentType) {
    throw 'Content type has not been set!'
  }
  if (contentType.includes('application/json')) {
    const body = await request.json()
    return body
  } else if (contentType.includes('form')) {
    const formData = await request.formData()
    let body = {}
    for (let entry of formData.entries()) {
      body[entry[]] = entry[1]
    }
    return JSON.stringify(body)
  } else {
    throw 'Content type not recognized!'
  }
}

/**
 * Handle JSON POST data
 * @param {Request} request
 */
async function handlePostRequest(request) {
  let json

  // Read form data
  try {
    json = await readRequestBody(request)
  } catch (error) {
    return new Response(error, {
      headers: { 'content-type': 'text/plain' },
      statusText: error,
      status: 500,
    })
  }

  // Send response
  return new Response(JSON.stringify(json), {
    headers: { 'content-type': 'text/json' },
    status: 400,
  })
}

Затем добавьте следующие HTTP-команды в test.http:

# Test invalid POST with no content type
POST http://localhost:8787/ HTTP/1.1

###

# Test valid POST request
POST http://localhost:8787/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@gmail.com",
  "message": "Such a great show. Keep it up!",
  "subscribe": false
}

###

Обязательно используйте ###для разделения каждой HTTP-команды. Запустите сервер разработки с помощью команды wrangler devили npm run dev. Запустите каждый URL. Следует ожидать следующих результатов:

  1. Запрос GET: возвращает сообщение об ошибке 404
  2. Запрос POST без типа содержимого: возвращает сообщение об ошибке 400 о типе содержимого
  3. Действительный запрос POST: просто возвращает отправленные данные POST JSON.

В настоящее время мы не выполняем никакой проверки данных JSON,

В настоящее время мы не выполняем никакой проверки данных JSON, которые поступают с запросом POST. Давайте исправим это на следующем шаге.

3. Проверка схемы

Для проверки данных в форматах JSON мы будем использовать схему JSON, открытый стандарт, который используется для определения структуры ваших данных. Определения схемы сравниваются с данными с использованием инструментов проверки, чтобы проверить, соответствует ли структура. В противном случае возвращается список ошибок проверки. Вы можете узнать больше об основах схемы JSON здесь.

Мы начнем с установки @cfworker/json-schemaвалидатора схемы JSON, который может работать в среде Workers. Как упоминалось ранее, в бессерверных средах выполнения обычно отсутствуют некоторые API-интерфейсы, необходимые для поддержки полноценной среды Node.js. Таким образом, команда Cloudflare Workers создала приложение, которое может работать на их платформе. Он основан на ajvвалидаторе JSON для Node.js.

Выполните следующую команду, чтобы установить пакет:

npm install @cfworker/json-schema

Поскольку нам нужно использовать importоператор, нам нужно изменить тип сборки Workers с «JavaScript» на «webpack». Это делается в wrangler.toml:

...
type = "webpack"
...

Затем давайте создадим сценарий с именем, validator.jsкоторый будет содержать определение нашей схемы и логику проверки. Вставьте следующий код:

import { Validator } from '@cfworker/json-schema'

const validator = new Validator(
  {
    type: 'object',
    required: ['firstName', 'lastName', 'email', 'message', 'subscribe'],
    properties: {
      firstName: { type: 'string' },
      lastName: { type: 'string' },
      email: { type: 'string', format: 'email' },
      message: { type: 'string' },
      subscribe: { type: 'boolean' },
    },
  },
  '2019-09', // draft version
  false, // stop processing after the first error
)

function validate(input) {
  const { valid, errors } = validator.validate(input)

  // reformat errors object for display
  const errs = errors.map(error => ({
    type: error.keyword,
    message: error.error,
  }))

  return {
    valid, // boolean for validation status
    errors: errs, // list of validation errors
  }
}

export default validate

Затем мы импортируем и используем validateфункцию в нашей handlePostRequestфункции. Откройте index.jsи обновите соответственно:

import validate from './validator'

async function handlePostRequest(request) {
  let json

  // Read form data
  try {
    json = await readRequestBody(request)
  } catch (error) {
    return new Response(error, {
      headers: {
        'content-type': 'text/plain',
      },
      statusText: error,
      status: 500,
    })
  }

  // Validate json inputs
  const results = validate(json)
  // Return 400 Error Response for invalid post request
  if (!results.valid) {
    return new Response(JSON.stringify(results), {
      headers: {
        'content-type': 'text/json',
      },
      status: 400,
    })
  }

  // Send response
  return new Response(JSON.stringify(json), {
    headers: {
      'content-type': 'text/json',
    },
    status: 200,
  })
}

Чтобы протестировать эту новую функциональность, мы добавим еще пару HTTP-команд. Просто добавьте это в test.httpфайл:

# Test invalid POST request - check missing data inputs
POST http://localhost:8787/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John"
}

###

# Test invalid POST request - check invalid types
POST http://localhost:8787/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe",
  "message": "Such a great show. Keep it up!",
  "subscribe": "false"
}

###

Наконец, убедитесь, что wrangler devсервер запущен, затем выполните все HTTP-команды. Ниже приведен пример ожидаемого ответа при неудачной проверке:

Наконец, убедитесь, что wrangler devсервер

Для действительного запроса POST это должно выполняться, как и раньше, то есть возвращать данные запроса JSON в своем ответе. В следующем разделе мы интегрируем почтовый сервис Mailgun.

Интеграция электронной почты

Создать приложение Workers, которое может отправлять электронные письма, довольно просто. Для этого нам не нужно устанавливать никаких новых пакетов. Мы просто воспользуемся сервисом REST API Mailgun. Сначала создайте файл email-service.jsи вставьте следующий код:

import htmlTemplate from './email-html-template.js'
import textTemplate from './email-text-template.js'

// Convert Javascript data object to a format that can be sent using HTTP
function urlEncodeObject(obj) {
  return Object.keys(obj)
    .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]))
    .join('&')
}

function sendMail(json) {
  const data = {
    to: TO_EMAIL_ADDRESS,
    from: FROM_EMAIL_ADDRESS,
    subject: 'New Contact: Online Guest Book',
    text: textTemplate(json),
    html: htmlTemplate(json),
  }

  const dataUrlEncoded = urlEncodeObject(data)
  const opts = {
    method: 'POST',
    headers: {
      Authorization: 'Basic ' + btoa('api:' + MAILGUN_API_KEY),
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': dataUrlEncoded.length.toString(),
    },
    body: dataUrlEncoded,
  }

  return fetch(`${MAILGUN_API_BASE_URL}/messages`, opts)
}

export default sendMail

sendMail Функция первой собирает всю информацию, необходимую для построения по электронной почте. Используя кодировку URL, информация кодируется в формат URL, который может быть отправлен через Интернет. Если вы посмотрите на собранную информацию, вы, возможно, заметили, что мы обращаемся к ряду постоянных переменных, которые мы не объявили. Это переменные среды, которые вводятся Cloudflare при запуске нашего скрипта. Их можно объявить двумя способами:

  1. Используяwrangler secret put команду. При запуске переменная среды будет загружена прямо в настройки вашего приложения Workers. Он также автоматически зашифрует значение.
  2. Второй вариант — сначала опубликовать ваше приложение с помощью wrangler publishкоманды. Затем на cloudflare.comперейдите в Панель управления > Рабочие > Нажмите «cloudflare-form-service» > » Настройки» > » Переменные среды«. Здесь вы можете ввести все необходимые переменные, необходимые для email-serviceзапуска скрипта. Вы можете оставить значения без изменений, если вы захотите изменить их позже, или нажмите кнопку шифрования, чтобы защитить токены.
Читайте также:  Запустить контейнер Docker как службу в Ubuntu

В приведенном выше примере я оставил свой незашифрованный

В приведенном выше примере я оставил свой незашифрованный, чтобы потом можно было изменить. Однако настоятельно рекомендуется использовать интерфейс командной строки wrangler для настройки переменных среды. Обратите внимание, что это будет сброшено позже, когда мы начнем определять наши промежуточные и производственные среды.

Далее нам нужно создать HTML и текстовые шаблоны. Они необходимы для форматирования нашего электронного письма, чтобы данные были презентабельными.

Создайте файл email-text-template.jsи вставьте следующий код:

const template = data => {
  return `
    Online Guest Book Contact
    --------------------------
    First Name : ${data.firstName}
    Last Name  : ${data.lastName}
    Email      : ${data.email}
    Message    : ${data.message}
    Subscribed : ${data.subscribed ? 'Yes' : 'No'}
`
}

export default template

Создайте файл email-html-template.jsи вставьте следующий код:

const template = data => {
  return `
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Email Template</title>
      <link
        rel="stylesheet"
        href="https://unpkg.com/modern-css-reset/dist/reset.min.css"
      />
      <style>
        body {
          background: #eee;
          color: #111827;
          display: flex;
          align-items: center;
          justify-content: center;
          min-height: 100vh;
          font-family: sans-serif;
        }
        div.container {
          background: #f9fafb;
          border-radius: 1rem;
          padding: 4rem;
        }
        .inline {
          display: flex;
          margin-top: 1.2rem;
        }
        .field {
          margin-bottom: 1rem;
        }
        .label {
          color: #374151;
          font-weight: bold;
        }
        .value {
          color: #374151;
          font-family: 'Courier New', Courier, monospace;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>Online Guest Book Contact</h1>
        <div class="inline">
          <div class="field">
            <div class="label">First Name</div>
            <div class="value">${data.firstName}</div>
          </div>
          <div class="field" style="margin-left:2rem">
            <div class="label">Last Name</div>
            <div class="value">${data.lastName}</div>
          </div>
        </div>
        <div class="field">
          <div class="label">Email</div>
          <div class="value">${data.email}</div>
        </div>
        <div class="field">
          <div class="label">Message</div>
          <div class="value">${data.message}</div>
        </div>
        <div class="field">
          <div class="label">Subscribed</div>
          <div class="value">${data.subscribed ? 'Yes' : 'No'}</div>
        </div>
      </div>
    </body>
  </html>
`
}

export default template

Наконец, обновите index.jsследующим образом:

...
import sendMail from './email-service'

async function handlePostRequest(request){
  ...
  // Send response
   try {
    const result = await sendMail(json)
    if (result.status == 200) {
      return new Response(
        JSON.stringify({ message: 'Message succesfully sent' }),
        {
          headers: { 'content-type': 'text/json' },
        },
      )
    } else {
      return new Response(
        JSON.stringify({ message: 'Message submission failed!', result }),
        {
          headers: { 'content-type': 'text/json' },
          status: 400,
        },
      )
    }
  } catch (error) {
    return new Response(error, {
      headers: { 'content-type': 'text/plain' },
      statusText: 'An error occurred',
      status: 500,
    })
  }
}

Вот ссылка на полный index.jsфайл, если вы не знаете, где разместить этот новый блок кода. Новый блок кода просто передавая данные request.jsonк sendMailфункции, а затем ждет ответа. В случае успеха отправляется сообщение об успешном выполнении. В противном случае возвращается сообщение об ошибке. catchБлок для отправки любого другого сообщения об ошибке, что мы не можем предвидеть.

Запустите wrangler devсервер и повторно выполните все HTTP-команды в test.http. Все должно работать как раньше, за исключением теста «Проверить действительный запрос POST». При выполнении вы должны получить следующий ответ JSON:

{
  "message": "Message succesfully sent"
}

Вы должны получить электронное письмо почти мгновенно. Проверьте свой почтовый ящик на что-то вроде этого:

Проверьте свой почтовый ящик на что-то вроде этого

Если вы используете песочницу для своего домена отправителя, электронное письмо, скорее всего, попадет прямо в вашу папку для спама. Зайдите туда, найдите его и подтвердите, что вы получили свое электронное письмо. В следующем разделе мы рассмотрим, как добавлять заголовки CORS в наши ответы API.

Добавление CORS в заголовки ответов

CORS (совместное использование ресурсов из разных источников) — это функция безопасности API, реализованная в браузерах, которая гарантирует, что веб-приложения имеют правильные разрешения для доступа к информации с сервера. До сих пор мы использовали только инструменты, отличные от браузера, для выполнения запросов Worker API без каких-либо проблем. Кроме того, выполнение запроса API между одним сервером и другим не вызывает никаких проблем, связанных с CORS. Однако, как только мы развернем наше приложение React и попробуем запросить наш Workers API с помощью запроса браузера, мы столкнемся с ошибками CORS.

Чтобы исправить это, нам нужно открыть index.jsв нашем приложении Workers и добавить следующее сразу после операторов импорта:

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'Content-Type',
  'Access-Control-Allow-Methods': 'POST',
  'Access-Control-Max-Age': '86400',
}

Затем нам нужно обработать предварительные запросы CORS, которые представляют собой механизм, который браузеры используют для проверки протоколов CORS и конкретных методов и заголовков, которые поддерживает наш сервер. Этот тип запроса выполняется с помощью OPTIONSметода. Обновите handleRequestфункцию следующим образом:

async function handleRequest(request) {
  if (request.method === 'POST') {
    return handlePostRequest(request)
  } else if (request.method === 'OPTIONS') {
    return new Response('OK', { headers: corsHeaders })
  } else {
    return new Response('Object Not Found', {
      statusText: 'Object Not Found',
      status: 404,
    })
  }
}

Наконец, для каждого ответа, возвращенного в коде, добавьте или добавьте заголовки CORS…corsHeaders, например:

return new Response('OK', { headers: corsHeaders }) // <-- Add like this or...
...
return new Response(
  JSON.stringify({ message: 'Message succesfully sent' }),
  {
    headers: { 'content-type': 'text/json', ...corsHeaders }, // <-- Append like this
  },
)

Убедитесь, что каждый возвращенный ответ имеет расширение corsHeaders. В противном случае вы столкнетесь с ошибками CORS при тестировании пользовательского интерфейса формы. См. Полный index.jsтекст для уточнения. Когда вы закончите, ваше приложение Workers будет готово к CORS и должно без проблем работать с любым веб-браузером.

В следующем разделе мы рассмотрим развертывание нашего приложения Workers.

Развертывание проекта

В этом разделе мы рассмотрим, как развернуть наше приложение Workers. Сначала мы начнем с использования бесплатного поддомена Workers, а затем будем использовать собственный домен. Мы также настроим промежуточную и производственную среды.

Развертывание службы работников обработки форм

Развернуть приложение Workers на серверах Cloudflare довольно просто. Все, что вам нужно сделать, это выполнить эту команду:

wrangler publish

Затем добавьте следующие HTTP-команды в test.http:

###

#-----------------------#
#                       |
# PUBLISHED HTTP TESTS  |
#                       |
#-----------------------#

# Test GET request
GET cloudflare-form-service.<subdomain>.workers.dev/ HTTP/1.1

###

# Test invalid POST request - check missing data inputs
POST cloudflare-form-service.<subdomain>.workers.dev/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John"
}

###

# Test valid POST request on published URL
POST cloudflare-form-service.<subdomain>.workers.dev/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@gmail.com",
  "message": "Such a great show. Keep it up!",
  "subscribe": false
}

Обязательно замените термин именем поддомена, которое вы использовали для регистрации своей учетной записи Cloudlflare Workers. После сохранения запускайте каждый из новых запросов, чтобы убедиться, что вы получите ожидаемые ответы. Если у вас хорошее интернет-соединение, каждый опубликованный запрос должен выполняться менее чем за секунду. Однако проверка «действительного почтового запроса» должна занять немного больше секунды, поскольку есть небольшая задержка, вызванная запросом электронной почты API, происходящим внутри handlePostRequestфункции.

В настоящее время наше приложение Workers работает в workers.devдомене Cloudflare. Если вы хотите опубликовать это в своем личном домене, нам сначала нужно настроить пару сред. На самом деле в этом нет необходимости, но рекомендуется иметь отдельные среды для тестирования и производства.

В Worker Environments ваше приложение будет развернуто в нескольких местах с использованием одного и того же кода, но с разными переменными среды. Среды, которые мы создадим, будут называться stagingи production. У каждого будет свой уникальный URL-адрес, к которому можно получить доступ следующим образом:

  • производство:https://cloudflare-form-service..workers.dev
  • постановка:https://cloudflare-form-service-staging..workers.dev

Обновите ваш wrangler.tomlследующим образом:

name = "cloudflare-form-service-dev"
type = "webpack"
account_id = "<ACCOUNT_ID>"

[env.staging]
name = "cloudflare-form-service-staging"
workers_dev = true

[env.production]
name = "cloudflare-form-service"
workers_dev = false
route = "https://contact-form-worker.example.com/"
zone_id = "<ZONE_ID>"

Замените все идентификаторы своими токенами и example.comсвоим персональным доменом. Вы можете заметить, что мы указали субдомен, которого на routeсамом деле не существует. Мы настроим это прямо сейчас. Просто зайдите на главную приборную панель Cloudflare, затем нажмите на DOMAIN вы добавили. Щелкните вкладку DNS, затем создайте новую запись следующим образом:

  • Type: CNAME
  • Name: contact-form-worker
  • Target: @

После нажатия кнопки Сохранить вам нужно будет опубликовать

После нажатия кнопки Сохранить вам нужно будет опубликовать свою производственную среду, используя следующую команду:

wrangler publish -e production

Используя routeуказанный в wrangler.toml, URL нашей производственной среды — cloudflare-form-service..workers.dev- будет сопоставлен contact-form-worker.example.com. Поскольку мы только что опубликовали наше приложение в новой среде, вам придется повторно загрузить ключи приложения среды, используя следующие команды:

wrangler secret put TO_EMAIL_ADDRESS --env production
wrangler secret put FROM_EMAIL_ADDRESS --env production
wrangler secret put MAILGUN_API_KEY --env production
wrangler secret put MAILGUN_API_BASE_URL --env production

Наконец, добавьте следующие HTTP-команды для тестирования вашего приложения в личном домене:

###

# Test GET request
GET contact-form-worker.example.com/ HTTP/1.1

###

# Test invalid POST request - check missing data inputs
POST contact-form-worker.example.com/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John"
}

###

# Test valid POST request on published URL
POST contact-form-worker.example.com/ HTTP/1.1
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@gmail.com",
  "message": "Such a great show. Keep it up!",
  "subscribe": false
}

Замените все example.comсвоим фактическим персональным доменом. Запустите все новые тесты и убедитесь, что все они дают ожидаемые ответы. В следующем разделе мы предоставим вам интерфейсный код, который вы можете использовать для тестирования своего рабочего приложения Workers.

Развернуть пользовательский интерфейс формы

Мы не можем завершить наш сервер обработки форм Workers, не протестировав его на реальном приложении. Я создал пользовательский интерфейс формы Cloudflare, который можно использовать для тестирования службы Workers. Чтобы запустить его локально, вам нужно сначала установить зависимости, затем создать.envфайл и разместить URL-адрес вашего приложения Workers:

VITE_FORM_ENDPOINT_URL=<place your workers application URL here>

Затем вы запускаете приложение локально с помощью npm run devкоманды. В качестве альтернативы вы можете развернуть его на такой платформе, как:

  • Страницы Cloudflare
  • Netlify
  • Vercel

Настройки сборки:

  • Команда сборки:npm run build
  • Папка сборки:dist

Убедитесь, что вы также загрузили требуемую переменную среды VITE_FORM_ENDPOINT_URL. Ниже приведен снимок экрана пользовательского интерфейса формы, развернутого на Cloudflare Pages.

Убедитесь, что вы также загрузили требуемую переменную среды

Если вы столкнулись с сообщением об ошибке, убедитесь, что:

  • все ваши ответы Workers имеют заголовки CORS
  • вы выполнили wrangler publishсвой проект приложения Workers
  • переменные среды были установлены

Заключение

Надеюсь, вы научились создавать и развертывать собственную службу обработки форм с уведомлениями по электронной почте с использованием бессерверных функций. Время, потраченное на это, может помочь вам значительно сэкономить на всех ваших потребностях в обработке форм. Есть еще много бессерверных функций, которые мы не рассматривали, например:

  • Рабочие КВ Склад
  • Триггеры Cron
  • Рабочие освобождены

Последние две службы позволяют выполнять бессерверные функции намного дольше десяти миллисекунд. На самом деле ограничений по времени нет, если вы не превышаете лимитов, которые могут помешать другим службам. Хотя Cloudflare Workers не может быть идеальной платформой для размещения традиционного внутреннего кода, они предоставляют множество возможностей для создания серверных решений, которые нелегко или невозможно реализовать на монолитных платформах.

Оцените статью
bestprogrammer.ru
Добавить комментарий