构建和维护您自己的网站是一个好主意。您不仅可以 拥有自己的平台,而且可以一路尝试 Web 技术。最近,我深入研究了无服务器函数的概念,从 我自己的网站 开始。我想分享我的成果以及我在此过程中学到的东西,这样您也可以动手尝试!
但首先,快速了解一下无服务器函数
无服务器函数(有时称为 lambda 函数或云函数)是您可以编写、托管和运行的代码片段,与您的网站、应用程序或任何其他代码无关。尽管名称如此,无服务器函数确实在 服务器上运行;但您无需构建或维护服务器。无服务器函数之所以令人兴奋,是因为它们消除了创建功能强大、可扩展的应用程序的大量工作量。
网上有很多关于无服务器函数的信息,而一个很好的起点是 CSS Trick 自己的指南:无服务器前端开发者的力量。
挑战:构建邮件列表注册表单
我从一个挑战开始我的旅程:我想在我的网站上有一个电子邮件列表注册表单。规则如下
- 它应该在没有 JavaScript 的情况下工作。我想看看仅使用 CSS 和 HTML 我能做到什么程度。渐进增强是可以的。
- 它不应该需要外部依赖项。这是一个学习项目,所以如果可能,我想编写 100% 的代码。
- 它应该使用无服务器函数。不要将数据发送到我网站的电子邮件列表服务客户端,让我们在服务器(无服务器)端进行!
认识团队:11ty、Netlify 和 Buttondown
我的网站使用名为 11ty 的静态网站框架构建。11ty 允许我在 HTML 中编写模板和组件,所以我们将使用它来构建我们的电子邮件表单。(Chris 最近写了一篇关于 他使用 11ty 的经验 的文章,如果您有兴趣了解更多,可以看看。)
然后,网站使用名为 Netlify 的服务部署,它是我们团队中的关键成员:控球后卫、四分卫、队长。这是因为 Netlify 具有三个相互协作的功能,共同实现了无服务器卓越
- Netlify 可以从 GitHub 仓库自动部署。这意味着我可以编写我的代码,创建拉取请求,并立即查看我的代码是否有效。虽然有 工具 可以本地测试无服务器函数,但 Netlify 使实时测试变得超级容易。
- Netlify 表单 处理我的网站收到的所有表单提交。这是无服务器等式的一部分:我无需编写代码来收集提交,只需使用一些简单的属性配置 HTML,剩下的就交给 Netlify 处理。
- Netlify 函数 允许我对来自表单的数据采取行动。我将编写一些代码将电子邮件发送到我的电子邮件列表提供商,并告诉 Netlify 何时运行该代码。
最后,我将使用名为 Buttondown 的服务管理我的电子邮件列表。它是一个简洁的电子邮件时事通讯提供商,具有易于使用的 API。
奖励:对于像我这样的个人网站,11ty、Netlify 和 Buttondown 都是免费的。你无法超越它。
表单
我的电子邮件订阅表单的 HTML 代码非常简洁,并且添加了一些 Netlify 表单才能正常工作的内容。
<form class="email-form" name="newsletter" method="POST" data-netlify="true" netlify-honeypot="bot-field">
<div hidden aria-hidden="true">
<label>
Don’t fill this out if you're human:
<input name="bot-field" />
</label>
</div>
<label for="email">Your email address</label>
<div>
<input type="email" name="email" placeholder="Email" id="email" required />
<button type="submit">Subscribe</button>
</div>
</form>
首先,我将 data-netlify
属性设置为 true
,告诉 Netlify 处理此表单。
表单中的第一个输入命名为 bot-field
。这会诱使机器人暴露自己:我告诉 Netlify 通过将 netlify-honeypot
属性设置为 bot-field
来监控任何可疑提交。然后,我使用 html hidden
和 aria-hidden
值将该字段隐藏在用户面前,使用和不使用辅助技术的用户都无法填写虚假输入。
如果表单在 bot-field
输入中提交任何内容,Netlify 会知道它来自机器人,并忽略该输入。除了这种保护层之外,Netlify 会使用 Askimet 自动过滤可疑提交。我不必担心垃圾邮件!
表单中的下一个输入命名为 email
。这就是电子邮件地址的输入位置!我已经指定了输入类型为 email
,并表明它是 required
;这意味着浏览器将为我完成所有验证,并且不会让用户提交任何其他内容,除了有效的电子邮件地址。

使用 JavaScript 进行渐进增强
Netlify 表单的一个很酷的功能是能够在用户提交表单时自动将他们重定向到“感谢”页面。但理想情况下,我希望让用户停留在页面上。我编写了一个简短的函数,用于在没有重定向的情况下提交表单。
const processForm = form => {
const data = new FormData(form)
data.append('form-name', 'newsletter');
fetch('/', {
method: 'POST',
body: data,
})
.then(() => {
form.innerHTML = `<div class="form--success">Almost there! Check your inbox for a confirmation e-mail.</div>`;
})
.catch(error => {
form.innerHTML = `<div class="form--error">Error: ${error}</div>`;
})
}
当我通过 form
值将我的电子邮件表单的内容提供给此函数时,它会使用 JavaScript 的内置 Fetch API 提交表单。如果函数成功,它会向用户显示一条友好的消息。如果函数遇到问题,它会告诉我的用户出现了一些错误。
每当用户单击表单上的“提交”按钮时,都会调用此函数
const emailForm = document.querySelector('.email-form')
if (emailForm) {
emailForm.addEventListener('submit', e => {
e.preventDefault();
processForm(emailForm);
})
}
此监听器渐进增强了表单的默认行为。这意味着,如果用户禁用了 JavaScript,表单仍然可以正常工作!

无服务器函数
现在我们已经有了有效的电子邮件提交表单,现在是时候使用无服务器函数进行一些自动化了。
Netlify 函数的工作方式如下
- 在项目中的 JavaScript 文件中编写函数。
- 通过项目中的 netlify.toml 文件告诉 Netlify 在哪里查找您的函数。
- 通过 Netlify 的管理界面添加您需要的任何环境变量。环境变量类似于 API 密钥,您需要对其保密。
就这样!下次部署网站时,该函数就可以使用了。
我的网站的函数将位于 functions 文件夹中,因此我的 netlify.toml
文件中有以下内容
[build]
base = "."
functions = "./functions"
然后,我将在 functions 文件夹中添加一个名为 submission-created.js 的文件。将文件命名为 submission-created 非常重要,这样 Netlify 才能知道每当发生新的表单提交时就运行它。您可以在 Netlify 的文档 中找到您可以针对其编写脚本的事件的完整列表。如果正确命名和配置了函数,您应该在 Netlify 的函数仪表板中看到它

submission-created.js 中的内容如下所示
require('dotenv').config()
const fetch = require('node-fetch')
const { EMAIL_TOKEN } = process.env
exports.handler = async event => {
const email = JSON.parse(event.body).payload.email
console.log(`Recieved a submission: ${email}`)
return fetch('https://api.buttondown.email/v1/subscribers', {
method: 'POST',
headers: {
Authorization: `Token ${EMAIL_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
})
.then(response => response.json())
.then(data => {
console.log(`Submitted to Buttondown:\n ${data}`)
})
.catch(error => ({ statusCode: 422, body: String(error) }))
}
让我们逐行看看。
第 1 行包含一个名为 dotenv
的库。这将帮助我使用环境变量。环境变量对于保存不想公开的信息(如 API 密钥)很有用。如果我在本地运行项目,我将在仓库中使用 .env
文件设置我的环境变量,并确保它列在我的 .gitignore
文件中。为了在 Netlify 上进行部署,我还需要在 Netlify 的 Web 界面中设置环境变量。

在第 2 行,我添加了一个名为 node-fetch
的小型库。这使我可以在节点中使用 Javascript 的 Fetch API,这就是我们将数据发送到 Buttondown 的方式。Netlify 会自动包含此依赖项,只要它列在我的项目的 package.json
文件中即可。
在第 3 行,我从环境变量对象 process.env
中导入我的 API 密钥。
第 4 行定义了函数。exports.handler
值是 Netlify 期望找到函数的地方,因此我们在此定义它。我们唯一需要的输入是 event
值,它将包含来自表单提交的所有数据。
在使用 JSON.parse
从 event
值中检索电子邮件地址后,我就可以将其发送给 Buttondown。这里我使用了之前导入的 node-fetch
库:我向 https://api.buttondown.email/v1/subscribers
发送 POST 请求,并在标头中包含我的 API 密钥。 Buttondown 的 API 功能不多,因此如果您想了解更多信息,阅读文档并不需要太长时间。
我的 POST 请求的主体包含我们检索到的电子邮件地址。
然后(使用简洁的 .then()
语法),我收集来自 Buttondown 服务器的响应。我这样做是为了诊断过程中发生的任何问题——Netlify 使得检查函数日志变得容易,因此经常使用 console.log
!

部署函数
现在我已经编写了函数、配置了 netlify.toml 文件并添加了环境变量,一切都准备就绪。部署非常简单:只需设置 Netlify 的 GitHub 集成,您的函数将在您的项目被推送到 GitHub 时部署。
Netlify 项目也可以使用 Netlify Dev 在本地测试。根据代码的复杂程度,本地开发可能更快:只需运行 npm i netlify -g
,然后运行 netlify dev
。Netlify Dev 将使用 netlify.toml 文件来配置和运行本地项目,包括任何无服务器函数。很酷吧?不过需要注意的是:Netlify Dev 目前无法在表单提交时触发无服务器函数,因此您需要使用 预览构建 来测试它。
未来展望
当提交新的电子邮件时,Buttondown 的 API 可能会有几种响应。例如,如果用户提交了一个已经订阅了列表的电子邮件,我很想能够在他们提交表单后立即告诉他们。
总结
总而言之,我只编写了大约 50 行代码,就可以在我的网站上提供一个功能完备的电子邮件简报订阅表单。我使用 HTML、CSS 和 JavaScript 编写了所有代码,而无需担心服务器端的问题。表单处理垃圾邮件,我的读者无论是否启用 JavaScript 都能获得良好的体验。
实际上可以 :) 我们在几周前发布了
netlify functions:invoke
:https://github.com/netlify/netlify-dev-plugin/#locally-testing-functions-with-netlify-functionsinvoke请解释一下,为什么如果我禁用 JS,事件监听器仍然有效?
因为函数运行在 Netlify 的后端基础设施(AWS)上。表单将向 Netlify 的后端发送 POST 请求,触发您的函数。
所有这些都可以使用 Netlify 免费计划运行吗?
可以,但它有每月 100 次提交的限制。下一个级别每月 19 美元,比 Formspree 更贵。
事实上,下一个级别每月 99 美元,可以无限提交。
每月 19 美元的专业版计划也有每月 100 次提交的限制 :(
这篇文章解释得不够清楚。这侧重于 Netlify 表单与函数的集成。也许完整的源代码会有所帮助。
下面的文章涵盖了所有信息。
我推荐 https://dev.to/twilio/how-to-send-text-messages-from-your-static-site-using-netlify-twilio-and-serverless-functions-24ci
https://github.com/stefanjudis/8-bit-revolution/blob/master/dist/index.html