一、为什么要从“能跑”升级到“稳定能用”
一开始,我们只是希望几个轻量网页能在线访问:照片墙可以实时上传和展示照片,新员工欢迎页可以让学员签到、上传头像,并在大屏上形成互动效果。 但当这些页面从“个人测试”走向“现场活动”时,问题就变了:不是能不能打开,而是能不能支撑几十到上百人同时访问、上传、刷新,并且重启后数据不丢。
这次实践的核心经验是:轻量服务器适合承载业务逻辑,但不适合把所有压力都扛在自己身上。 数据应该进入 MySQL,图片与头像应该进入 COS,访问加速交给 CDN。服务器只负责“接收请求、处理逻辑、写入记录、返回结果”。
二、最终架构:服务器做逻辑,MySQL 存数据,COS 存文件,CDN 做分发
最终架构:Nginx / SSL / Node 服务 / MySQL / COS / CDN 各司其职。
Photosync 照片墙
照片记录进入 MySQL,图片文件进入 COS,页面通过 CDN URL 加载图片。这样即使服务重启,照片记录仍然存在。
NSTWelcome 新员工欢迎页
签到信息进入 MySQL,头像上传到 COS,数据库只保存头像 CDN 地址,大屏刷新后仍能重新加载所有用户。
三、落地过程中的关键步骤
这次不是一次性写完所有代码,而是分阶段验证。先确认 Node 服务能跑,再接 MySQL;MySQL 成功后,再接 COS;COS 上传成功后,再配置 CDN 域名和 SSL;最后才做重启和并发验证。
可复用方法:先跑通服务,再接数据库,再接文件存储与 CDN,最后做验证。
四、这次踩过的坑
- 不要把内存当数据库。 原来用户和照片记录存在 Node 内存里,重启就丢;接入 MySQL 后才真正持久化。
- 不要把图片长期压在服务器本地。 上传文件如果都在轻量服务器本地,会带来存储、带宽和迁移问题;COS 更适合保存图片。
- CDN 根路径返回 AccessDenied 不一定是错。 COS 根目录不展示文件列表,应该用真实对象路径验证。
- TypeScript 不能直接用 node 跑。 宝塔 Node 项目如果直接运行 server.ts 会报错,需要用 npx tsx server.ts 或 start.cjs 包一层。
- 端口冲突要先排查。 3000、3080 等端口被旧进程占用时,新服务会启动失败,需要用 ss -lntp 和 pm2 清理。
- health 接口非常重要。 /api/health 可以快速判断数据库、COS 配置和后端服务是否正常。
最关键的转变是:不要把轻量服务器当成“大仓库”,而要把它当成“调度中心”。数据、文件、分发分别交给更适合的基础设施。
五、以后做类似项目的推荐流程
以后如果再做活动签到、照片墙、互动大屏、轻量学习工具,可以复用这套方法:
- 先明确访问入口:独立子域名,还是主站路径。
- 先跑通 Node 服务,再做 Nginx 反向代理。
- 业务数据一开始就设计进 MySQL。
- 图片、头像、音频等文件尽量进入 COS。
- 对外展示图片统一使用 CDN 域名。
- 每次上线前备份文件,并用 health 接口、数据库查询、重启测试做最终确认。
六、最终收益
通过这次升级,Photosync 和 NSTWelcome 都从“能在线访问的页面”变成了“具备基础工程稳定性的轻应用”。 对于 100 人左右的现场签到、上传头像、照片墙互动场景,这套架构已经比单纯靠本地文件和内存状态可靠得多。
它的价值不只是这两个页面本身,更重要的是沉淀了一套可以复用的方法:轻量服务器负责逻辑,MySQL 负责数据,COS 负责文件,CDN 负责分发。