如何在没有服务器的情况下为静态网站添加动态功能
静态网站目前正受到人们的青睐,这是有原因的。一个包含HTML、CSS和JavaScript文件的文件夹,加载速度很快,托管成本也很低,而且几乎不可能出现故障。 像 Astro 、 Eleventy 和 Hugo 这样的工具,能够利用Markdown文件和模板帮您生成这样的网站结构。而Netlify、Vercel以及Cloudflare Pages等托管服务,则可以通过内容分发网络来提供这些生成的网站内容,而且通常还是免费的。 不过,您的网站还需要具备实际的功能。读者可能想要留下评论,或者有人想通过电子邮件与您联系。也许您还想实时显示价格信息,需要用户登录后才能查看某些页面,或者在网站发布之前收
静态网站目前正受到人们的青睐,这是有原因的。一个包含HTML、CSS和JavaScript文件的文件夹,加载速度很快,托管成本也很低,而且几乎不可能出现故障。
像Astro、Eleventy和Hugo这样的工具,能够利用Markdown文件和模板帮您生成这样的网站结构。而Netlify、Vercel以及Cloudflare Pages等托管服务,则可以通过内容分发网络来提供这些生成的网站内容,而且通常还是免费的。
不过,您的网站还需要具备实际的功能。读者可能想要留下评论,或者有人想通过电子邮件与您联系。也许您还想实时显示价格信息,需要用户登录后才能查看某些页面,或者在网站发布之前收集用户的电子邮件地址。
大多数开发者在这种情况下都会选择使用后端技术。他们会搭建一个Express应用程序,添加数据库,并选择合适的托管方案。这样一来,他们就拥有了自己的服务器,而服务器是需要长期维护的。
不过好消息是,很多时候您其实并不需要这样的服务器。对于小型网站来说,大多数动态功能即便没有自己的服务器也能正常运行。因此,下面我们来探讨一下如何解决这些问题。
目录
静态并不意味着无法实现动态功能
“静态”这个词描述的是您的HTML代码是如何传输到浏览器的,而不是这些代码在浏览器中被执行后会发生什么。一个静态网站仍然可以运行您需要的所有JavaScript代码,它可以获取数据、重新生成页面内容、响应用户的点击操作,也可以与任何公共API进行交互。
但它有一件事是无法做到的,那就是在页面被发送给用户之前先运行您的代码。这意味着它无法隐藏某些信息、查询私有数据库,也无法根据请求者的身份来做出不同的处理。
正是这个限制决定了静态网站的设计方式。一旦您清楚地了解了这一点,剩下的问题就都很容易解决了:有些功能应该由浏览器本身来完成,有些则可以通过租用的服务来实现,而还有一些功能则需要在一个私密的环境中运行。
从浏览器已有的功能入手
在添加任何新的技术组件之前,请先了解当前所使用的平台——因为现代浏览器的功能远比我们大多数人所意识到的要强大得多。
fetch API可以用来从任何公共接口获取JSON数据。元素可以让您无需使用任何第三方库就能创建可交互的模态窗口,而元素则可以实现折叠式菜单的功能。如今,CSS已经能够处理固定标题、滚动动画以及容器查询等功能,而这些功能在过去都是需要借助JavaScript来实现的。
很多看似需要后端处理的功能,其实只需要进行一次数据获取请求,并使用模板字符串即可实现。天气插件、GitHub活动动态、货币转换器、实时比分显示工具,或是Mastodon的时间线功能:所有这些都可以通过浏览器顺利运行,因为相关数据都是公开的,而且调用这些接口也不需要任何密钥。只要编写好数据获取代码,妥善处理加载过程及可能出现的错误情况,问题就能迎刃而解。
处理表单提交
对于大多数静态网站来说,表单处理往往会成为第一个遇到的障碍,因为用户提交的表单数据必须被存储在访客无法看到的地方。你不能在客户端代码中存放数据库密码,也不能直接通过浏览器发送电子邮件。
幸运的是,这个问题已经被多次解决过了,大多数静态网站托管服务都会帮你处理表单相关事务。使用Netlify Forms时,只需要在表单标签中添加一个额外的属性即可。之后,Netlify会捕获每一份提交的表单数据,将其存储在控制面板中,并要么通过电子邮件通知你,要么触发Webhook接口。
不过有时候,你可能需要更多的功能。垃圾邮件过滤、文件上传、条件逻辑处理、多步骤流程设计、表单内集成支付功能,或者需要将数据直接导入电子表格……这些需求往往意味着你需要使用专门的工具来满足它们。通过查看这些优秀的表单构建工具,你可以对比各种选项,因为真正的区别在于这些工具所提供的逻辑处理能力、集成功能,以及你对自己编写的前端代码能拥有多少控制权。
无论如何,最终的选择还是取决于你是否愿意自己负责相关功能的实现。如果你自己编写表单处理的后端代码,那么你就能够完全掌控数据验证、请求速率限制、垃圾邮件过滤机制、数据存储方式、警报通知功能,以及符合GDPR规定的数据删除流程。不过,对于一个简单的联系表单来说,这样做未免有些大费周章。只有当表单成为你产品的重要组成部分时,才值得自己动手开发;而如果表单只是人们用来联系你的工具,那么租用现成的服务才是更合理的选择。
其余场景下的无服务器函数
迟早你会需要运行一些代码来处理某些特定任务——比如在数据发送给浏览器之前对其进行修改,或者隐藏API密钥。而无服务器函数正是为了解决这类问题而存在的,它们使你能够以最简单的方式让静态网站具备更多的动态功能。
你只需要将代码文件放入指定的文件夹中,托管服务就会在下次部署时将其转换成一个URL地址。这样的设置方式在Netlify Functions、Vercel Functions以及Cloudflare Pages Functions中都是通用的。代码量也会保持得很少:
export default async function handler(request) {
const res = await fetch("https://api.example.com/data", {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
const data = await res.json();
return Response.json({ total: data.items.length });
}
你的密钥存储在主机上的环境变量中,因此浏览器在调用 `/api/handler` 时根本看不到这个密钥。既不需要维护任何服务器,也不需要更新操作系统,更不会在平时产生任何费用。
对于任何需要使用凭证的功能来说,这种架构都是理想的选择。你可以利用它通过 Resend 或 Postmark 发送邮件,调用 AI 模型,验证 Webhook 签名,或者代理那些密钥否则会在一天内就被泄露的付费 API。
可租赁的数据库与登录服务
人们通常认为状态管理功能需要服务器来支持,但实际上并非如此。Supabase 通过 REST API 和行级安全机制来实现 Postgres 的状态管理。这些规则直接存储在数据库中,因此你可以通过浏览器进行查询而无需担心安全性问题。Firebase 采用不同的数据模型实现了类似的功能,而 Cloudflare D1 和 Turso 则在边缘节点提供了 SQLite 支持。
登录功能也遵循同样的模式。Clerk、Auth0 和 Supabase Auth 都通过客户端 SDK 来处理会话管理、密码重置、社交登录以及双因素认证等功能。认证机制的实现确实非常复杂,因此使用经过审计的服务来处理这些功能并不是偷懒,而是明智的风险管理措施。
评论、搜索与支付功能
对于最后这几类常见的功能,也有简单的解决方案。Giscus 只需要使用一个脚本标签,就能将 GitHub 的讨论区转换为评论框,而且完全不需要数据库。Pagefind 会在你的网站构建过程中生成搜索索引,并将其作为静态文件发布,因此运行时进行全文本搜索不会产生任何费用。
Stripe 可以处理所有的支付事务。通过 Payment Links 和 Checkout 功能,你可以使用简单的链接来销售商品,而 Stripe 会负责处理信用卡信息、税费以及开具收据等工作。你的网站根本不需要接触任何信用卡数据。
了解何时该升级系统
这种架构确实存在上限,你应该清楚这一点,而不是试图强行突破它。当出现以下情况时,你就应该考虑升级了:你的业务逻辑分散在六种不同的服务中;每月的 SaaS 费用已经超过了购买小型服务器的成本;系统的冷启动时间过长,影响了用户的体验;或者你需要执行耗时较长的任务、使用队列系统,或者需要保持连接数小时以上的socket。到了那个时候,使用传统的应用服务器会更加方便,所以应该及时进行升级。
在之前,这种架构确实能为你带来很多实际的好处。你的网站默认情况下就能保持较高的运行速度,安全风险也会降到最低,你可以将更多的精力投入到产品本身的开发中,而不是系统基础设施的维护上。先从浏览器开始使用这个架构,当需要使用密钥时再添加相应的功能,而对于那些复杂的部分,则可以选择租赁服务来使用。
希望你喜欢这篇文章。你可以通过 在 LinkedIn 上与我联系 。
相关文章
《设计模式手册:通过C#代码示例学习常见的设计模式》
设计模式是针对软件设计中常见问题的、可复用的解决方案。可以把它们看作是蓝图:并非完整的代码,而是经过验证的模板,你可以根据自己的需求将其调整过来,用于解决自己代码库中的特定问题。 这本手册旨在帮助大家切实理解软件设计模式。我编写这本书是为了所有开发者,无论你使用哪种编程语言。书中的示例是用C#编写的,但这里提到的每一个概念同样适用于Python、Java、TypeScript、Go等语言。 源代码可以在这里找到: github.com/Clifftech123/design-patterns-handbook 。 需要注意的事项: 设计模式本身并不是代码。 它们是一种思考代码结构的方式,是解决
阅读全文
jQuery的发展历程:这个小小的库是如何彻底改变网页开发领域的?
jQuery由John Resig创建,于2006年正式发布。它是一个JavaScript库,能够简化HTML操作、事件处理、动画效果以及Ajax功能的实现。由于提供了跨浏览器的通用API,jQuery极大地便利了网页开发工作。尽管随着现代框架的兴起,其使用频率有所下降,但如今仍有大量网站在使用jQuery。 作者:Daniel Curtis
阅读全文
构建者设计模式:构建复杂对象的一种更有效的方法
有些对象非常简单,比如字符串、数字或布尔值。你可以用一行代码创建它们,然后继续进行其他操作。 而另一些对象则完全不简单。例如,一个轮播组件就需要包含项目数量、项目生成函数、控制器、高度、视图窗口比例、自动播放设置、页面切换回调函数以及无限滚动配置等信息。再比如,一个HTTP请求需要URL地址、请求头信息、认证令牌、请求体内容、超时时间以及重试逻辑。又或者,一条通知消息需要标题、正文、图标、发送渠道、优先级、声音效果、振动功能以及操作按钮等等。 当你需要构建这类对象时,一种常见的方法是使用带有大量参数的构造函数。这种方法虽然可行,但随着对象结构变得越来越复杂,就会带来一系列问题:这些参数很难区分
阅读全文
OpenTelemetry的工作原理:一份全面的指南
如果你是一名软件开发人员或DevOps工程师,那么你很可能已经听说过OpenTelemetry。在讨论可观测性、监控或分布式系统的调试时,这个术语经常会被提及。 你可能也知道它的基本定义,但了解OpenTelemetry是什么与真正理解它的运作原理其实是两回事。 读完本指南后,你将能够明白OpenTelemetry是如何从端到端工作的——从请求进入你的应用程序的那一刻起,直到这些数据被显示在可观测性后端系统中。你还会了解到追踪信息、时间跨度、上下文传播机制以及数据导出工具是如何共同构成一个完整的处理流程的。 如果你完全不了解OpenTelemetry,也别担心:接下来的部分会帮助你快速掌握相关
阅读全文