回到2021年,一个客户来找我,提出了看起来很直接的需求:"我们需要一个拍卖网站。像eBay一样,但是垂直领域,古董摩托车配件。"三个月、两个被放弃的原型和一次真正令人尴尬的生产故障之后,我得出了想法。很强烈的想法。最后我们成功了,但我现在不会用同样的方式构建它。一点都不会。
关键要点:2026年的拍卖平台使用Next.js、带实时通道的Supabase用于实时竞价和Stripe;难点不在技术栈,而在并发环境下的竞价状态完整性。
拍卖平台难度被严重低估了。从表面上看,它只是列表、竞价和计时器。但当两个用户在毫秒内竞价,或你的WebSocket连接在倒计时归零时断开,或你的支付处理器在支付过程中超时时,突然你得向非常愤怒的卖家解释他们的1967年BSA Lightning为什么以12英镑成交。所以让我逐个工具、逐个决策来详细讲解我在2026年会如何构建。
---
核心架构决策:单体还是服务?
不要让任何人为第一版本向你兜售微服务。我是认真的。
我反复见过这个错误:创始人雇了一个顾问,顾问在白板上画出八个独立的服务,大家都点头,六个月后什么都没上线,因为团队在一个只有40个用户的平台上调试服务间延迟。对于拍卖MVP甚至是中等规模的产品(比如每月不到50,000活跃用户),模块化单体是正确的选择。
我会选择:前端和API层用Next.js,Node.js后端。不是因为它时尚。而是因为Next.js 14+中的服务器组件模型确实降低了拍卖列表页面的复杂度,这些页面SEO很重要,你希望那些拍品描述被索引。API路由处理较轻的任务;重型实时内容在别处(稍后我会讲更多)。
数据库?PostgreSQL。任何事务性应用都用PostgreSQL。拍卖涉及深层次的关系结构:用户、拍品、竞价、底价、发票,你希望外键约束做真正的工作,而不是凭感觉的应用逻辑。我在2026年会在Supabase上运行它,因为你得到Postgres、行级安全和实时订阅层都内置了,这把原本需要三个独立基础设施关注点的东西折叠成一份账单。
---
实时竞拍:会让你崩溃的部分
这是大多数拍卖平台失败的地方。或至少是跛行的地方。
根本问题:竞价必须感觉是即时的,必须一致,必须正确处理竞态条件。如果两个用户在同一毫秒提交竞价,其中一个赢。数据库决定谁赢。不是前端,不是负载均衡器,是数据库,通过用SELECT FOR UPDATE写的正确事务。
对于实时层本身,我在2026年会用Ably而不是自己开发原生WebSocket。我在Seahawk的一个房产拍卖项目中在2022年试过自己开发的方法,自托管socket.io、Redis发布订阅,各种都有。一切都很好直到出问题。Ably给你保证的消息顺序、连接状态恢复(所以如果竞价者的手机在拍卖中途从WiFi切换到4G,他们不会无声地错过中标),和一个明智的仪表板。大规模的定价是真实的成本,但对大多数拍卖运营商来说相比基础设施复杂度是小事。
处理"秒杀"问题
拍卖狙击,在最后几秒钟下注,对你的客户来说是功能还是缺陷取决于他们。eBay出名的是允许它。很多专业拍卖行在最后一分钟有竞价时会把计时器延长30-60秒。这叫"软关闭"或"反狙击"逻辑。从第一天就构建它。规则很简单:
- 竞价在剩余少于 N 秒时到达
- 交易确认竞价有效且为最高出价
- 拍卖结束时间延长 N 秒
- 新的结束时间通过 Ably 广播给所有连接的客户端
这大概是 40 行服务器逻辑。跳过它并在后期拼凑上去会很麻烦。
---
支付:别想太复杂
我见过很多人在拍卖网站上采用花哨的支付方案,因为拍卖有古怪的需求——你需要提前获取支付详情,只在拍品成交时才收费,可能需要持有保证金,如果被出价高于就可能需要立即退款。这些都是真的。都可以用 Stripe 在不离开 Stripe 文档的情况下解决。
2026年Stripe仍然是绝大多数拍卖运营者的正确选择。具体来说:
- 用于标准出价到收费流程的Stripe Payment Intents
- capture_method: manual来授权卡而不收费(对于保证金冻结至关重要)
- 如果你正在构建一个多个卖家收到付款的市场,可以使用 Stripe Connect
我要指出的一点是:除非你有法律建议说必须这样做,否则不要在一开始就授权卡片支付全部拍品价值。只授权定金(拍卖界通常是 10-25%),然后在拍品成交后才扣款或取消。你的卡片拒绝率会因此下降。
对于高价值的拍卖行、古董车、艺术品之类的,你需要支持银行转账。Stripe 现在通过他们的支付链接和发票产品能做得相当好,但对账时你还是需要人工介入。为此搭一个简单的管理员队列就行;别自动化那些不需要自动化的东西。
---
搜索和筛选:用 Typesense,不是 Elasticsearch
说实话,拍卖平台上的搜索问题被低估了。用户需要按类别、当前价格、剩余时间、状况、地点进行筛选。而且要快。
Elasticsearch对大多数拍卖网站来说过度设计,而且是真正的运维噩梦。我会用Typesense。它是开源的,你可以在6美元的DigitalOcean droplet上自托管或使用Typesense Cloud,搜索质量对于目录风格的数据来说很出色。通过简单的变更数据捕获钩子或每30秒的cron任务将你的PostgreSQL拍品表同步到Typesense(拍卖拍品价格的实时同步很好但对于搜索来说很少必要)。
Typesense 有一个开箱即用处理不好的地方:仅限自提物品的地理搜索。它确实有地理筛选功能,但如果你的拍卖网站有大量"仅限本地取货"的库存,早期花半天时间配置这个。我没有,在 2023 年的一个园艺机械拍卖网站上,后来我们事后改造时花了两倍的功夫。
---
基础设施和托管
这是我 2026 年的默认配置:
- 前端和 API 路由用 Vercel 上的 Next.js,零配置部署,每个分支都有预览 URL,必要时用边缘函数
- 用于 PostgreSQL 和身份验证的 Supabase
- 用于 WebSocket 的 Ably
- 用于搜索的 Typesense Cloud
- Cloudflare 在最前面,免费层就能处理 DDoS、图片优化和缓存,毫不费力
- Uploadcare 或 Cloudinary 用于卖家上传的拍品图片(2026 年请别再把用户上传存在自己服务器上了)
这个技术栈没有 Kubernetes、没有自管 Redis 集群、不需要招 DevOps。一个开发者或小团队就能运行它。最关键的是,它能扩展而不需要重新架构。当你被行业出版物报道,一小时内 8000 人涌入你的网站时,Vercel 和 Supabase 会搞定流量激增。
一个我经常看到的基础设施错误
人们容易忽视后台任务。拍卖结束事件不是用户触发的,它们在特定时间戳发生,在服务器端。你需要一个可靠的任务调度器。2026 年我会用 Inngest。它处理基于时间的触发、重试,还给你一个真正有用的事件日志,用来调试"为什么拍品 447 没有给赢家发邮件就结束了"。别在你的服务器上用简单的 cron。服务器重启时,cron 的状态就没了。
---
管理员和卖家工具
卖家需要创建列表、上传图片、设置底价和查看出价历史。买家需要关注列表、出价提醒和发票下载。这些不是光彩的功能。但这些是客户在周四晚上9点打电话给你时会投诉的功能。
管理后台,我会在 Retool 或自定义 Next.js 仪表板之上轻量级构建,取决于预算。Retool 真的很快就能搭起来,80% 的拍卖管理任务——批准列表、管理用户、作废出价——都能处理,代码不多。对于任何面向客户的东西,我会在 Next.js 中好好构建,因为 Retool 嵌在 iframe 里不是好的用户体验。
邮件通知、出价被超、拍品即将结束、发票已就绪,2026 年我会用 Resend。它大约 18 个月前在我的技术栈中取代了 SendGrid,我再也没回头看过。开发者体验明显更好,可投递性也很稳定。
---
拍卖特定的安全考虑
拍卖平台会吸引出价操纵尝试。刷单(卖家用虚假账户抬高自己拍品价格)、账户接管来进行欺诈性赢价出价,以及支付欺诈都是真实存在的,相比典型的电商来说不成比例地常见。
有几件事我会从一开始就设计进去:
- 出价提交的速率限制,每用户每分钟每拍品最多 N 次出价,在 API 层强制。Upstash Redis 很适合这个;它有一个专门构建的速率限制库。
- 竞标前要求邮箱验证,听起来很明显,但能阻止相当数量的滥用行为
- 通过 Stripe Radar 进行欺诈评分,Stripe 已经内置了这个功能,直接使用就行
- IP 和设备指纹识别用于检测可疑账户集群,如果你的业务规模达到了一定程度,FingerprintJS Pro 的成本是值得的
说实话,最重要的是日志。记录每一次竞价尝试、每一次失败的支付、每一次账户操作。当出问题的时候(肯定会出问题),你需要一份完整的审计日志。Supabase 内置的日志加上 Axiom 的轻量级设置就能搞定,不需要花太多力气。
---
常见问题
小型本地拍卖网站的最小可行堆栈是什么?
如果你在为一个本地拍卖行构建系统,假设有 200 个用户和每周的销售,你不需要 Ably 或 Typesense。WordPress 加上像 Auctions for WooCommerce 这样的插件能带你走很远。我为地区拍卖行、古董行、农机设备那类的设置过三个这样的系统。一旦你需要在高负载下进行真正的实时竞价,你会很快超出这个方案的能力。
我可以用Firebase代替Supabase吗?
可以的。Firebase 的 Firestore 其实对实时竞价状态来说是个合理的选择。我在 2026 年更倾向于 Supabase 的原因是 SQL,拍卖数据有大量的关系结构(地块属于销售,竞价属于地块和用户,发票引用竞价),而从文档数据库查询这些关系会很复杂。但如果你的团队已经对 Firebase 很熟悉,就别为了换而换。
我应该如何处理拍卖结束时间的时区问题?
所有时间数据都存储在UTC。永远都是。通过浏览器用用户的本地时区显示。这听起来很明显,但我还是在大约五分之一的项目中看到做错了。现代浏览器中的Intl.DateTimeFormat API可以处理显示部分,不需要任何库。
我需要一个移动应用吗?
MVP 阶段不需要。一个设计良好的渐进式网应用加上推送通知(通过 Web Push API)能满足竞价者在移动端实际需要的 90%。原生应用以后再考虑,如果业务确实需要的话。我会在那一天到来时使用 Expo 和 React Native,跨 iOS 和 Android 的共享代码库,而且团队已经熟悉 React。
---
在线拍卖运营是个正当的工程挑战,只是被一个看似简单的界面所掩盖。竞价界面就是三个按钮和一个数字。下面的所有东西——一致性、公平性、实时状态、欺诈防止——才是真正的工作所在。从一开始就把技术栈搞对,其他的就只是功能。搞错了,你就会成为那个跟卖家解释为什么他们的地块以 £12 成交的人。
构建无趣的基础设施。在其之上构建有趣的产品。
