Несколько недель назад я написал в блоге о создании универсального обработчика форм с помощью OpenWhisk. Идея заключалась в том, что вы могли указать любую форму на действие, и она собирала данные формы и отправляла результаты по электронной почте. Одна из проблем с моим действием заключалась в том, что оно работало только через HTTP-вызов к конечной точке. Это сделало его пригодным для простого вызова Ajax из JavaScript, но упустило одну из крутых функций, которые предоставляет большинство сервисов обработки форм — возможность перенаправления на другой URL-адрес после завершения.
Оказывается, поддержка теперь доступна в OpenWhisk в виде новой функции веб-действий. Сотрудник IBM Родрик Раббах написал отличный пост об этой функции здесь: Бессерверные обработчики HTTP с OpenWhisk. Также обязательно ознакомьтесь с его продолжением здесь: Веб-действия: бессерверные веб-приложения с OpenWhisk.
Инструкцию повторять не буду, но по сути она сводится к нескольким изменениям:
- Во-первых, при создании (или обновлении) действия добавьте
--annotation web-export true
- Во-вторых, выяснить URL. Ваш URL-адрес будет https://openwhisk.ng.bluemix.net/api/v1/experimental/web/NAMESPACE/PACKAGE/ACTION.TYPE. Если вы не используете пакет для своего действия, используйте
default
. Значение TYPE может быть одним из json, html, text или http.
В принципе, это все. (Есть еще, но опять же, см. пост Родрика). Учитывая, что мои действия в основном уже были выполнены, модификации были довольно простыми. Я поделюсь всем действием в конце, а вот моды, которые я добавил.
Сначала я просто ищу новый параметр _next. Если указано, значит, мы хотим перенаправить после обработки формы. Я сделал это необязательным, чтобы по-прежнему поддерживать версию Ajax, которую я создал изначально.
let next = '';
if(args['_next']) next = args['_next'];
Затем я просто ищу это, когда закончу:
if(next === '') {
resolve({result:'Ok'});
} else {
resolve({
headers: { location: next},
code: 302
});
}
Последним шагом было обновление моего действия с помощью нового кода и этого нового флага, чтобы открыть его как веб-действие. Я изменил свою форму, чтобы пропустить использование JavaScript для отправки и просто опубликовать новый URL:
<form id="contactForm" action = "https://openwhisk.ng.bluemix.net/api/v1/experimental/web/[email protected]_My%20Space/default/sendmail.http" method="post">
<input type="hidden" name="_next" value="https://www.raymondcamden.com">
Обратите внимание на использование HTTP в качестве типа контента. Я не отправляю обратно HTML, а заголовки HTTP. Если бы я хотел создать динамическую страницу «спасибо», я бы вместо этого использовал расширение HTML. Значение _next, которое я использовал, — это просто мой блог, но в реальной ситуации это была бы страница, специально предназначенная для благодарности пользователю за его отзыв.
И это все. Это отличное дополнение к платформе, и мне не терпится еще немного попинать шины. Вот полный источник действия, и, как всегда, если у вас есть какие-либо вопросы, комментарии или предложения, просто добавьте комментарий ниже.
//SendGrid API Key var SG_KEY = 'SG.secretkeysbetweenyouandme';
//people we are allowed to email var RECIPS = ["[email protected]","[email protected]"];
var helper = require('sendgrid').mail;
function main(args) {
let from_email = new helper.Email(RECIPS[0]); let to_email = new helper.Email(RECIPS[0]);
let next = ''; if(args['_next']) next = args['_next'];
/* Ok, so args will be our form data. Look for a few special item */
if(args["_from"]) { from_email = new helper.Email(args["_from"]); }
if(args["_to"]) { if(RECIPS.indexOf(args["_to"]) === -1) { return {error:"Invalid _to address: "+args["_to"]}; } else { to_email = new helper.Email(args["_to"]); } }
let subject = 'Form Submission';
if(args["_subject"]) { subject = args["_subject"]; }
/* Now loop through the rest of the args to create the form submission email. */
//todo: make date a bit prettier let date = new Date(); let content = ` Form Submitted at ${date} -------------------------------- `;
for(let key in args) { //blanket ignore if _* if(key.indexOf("_") != 0) { content += ` ${key}: ${args[key]} `; } }
let mailContent = new helper.Content('text/plain', content); let mail = new helper.Mail(from_email, subject, to_email, mailContent); let sg = require('sendgrid')(SG_KEY);
return new Promise( (resolve, reject) => {
var request = sg.emptyRequest({ method: 'POST', path: '/v3/mail/send', body: mail.toJSON() }); sg.API(request, function(error, response) { if(error) { console.log(error.response.body); reject({error:error.message}) } else { console.log('got to good result, next is '+next); /* new logic - handle possible redirect */ if(next === '') { resolve({result:'Ok'}); } else { resolve({ headers: { location: next}, code: 302 }); } } });
});
}
exports.main = main;
Эта запись первоначально появилась в моем блоге по адресу https://www.raymondcamden.com/2017/02/15/building-a-form-handler-service-in-openwhisk-part-two