2023 年 12 月 21 日上午,node-server-demo 在四十二分钟里完成了九次提交。
第一条记录是初始化仓库。六分钟后,Express 入口、路由和静态页面同批进入代码库;接下来的提交补了教程、十张截图、Git 忽略文件和图片 CDN。十点零九分,最后一条提交仍然只是更新文档。此后这个仓库没有再往前走。
旧文章把它写成一份从路由讲到部署、日志和回滚的 Node.js 笔记。重新打开固定提交后,我更想记录它当时实际做到了哪里。那份代码很短,短到每个缺口都看得见。
五条能走通的路径
入口文件使用 Express 4.18.2,端口直接写成 8080。根路径返回仓库里的静态 HTML;GET /get 读取查询参数 a,再原样送回;POST /post 接收 JSON,也原样返回。另有两个 Router,分别挂在 /app 和 /admin,各提供一条固定文本的登录路径。
这组路由没有业务数据,也没有身份校验。它更像一张后端地图:请求从哪里进来,如何按前缀分到不同文件,查询参数和 JSON body 怎样被 Express 读到,静态文件又怎样由服务端返回。
教程 Markdown 保存了当时的操作顺序:初始化 package.json,安装 Express,写 GET 和 POST,拆出两个路由文件,再加入静态页和 Vercel 配置。十张截图分别记录了终端、请求工具、目录结构和部署页面。它们比今天这篇文章更接近那次练习的现场,也让“做过什么”不必依赖后来补出的感受。
仓库同时保存了几处没收好的尾巴
README 写着可以执行 npm start,package.json 却没有 start 脚本。唯一的 test 脚本会打印 Error: no test specified,然后主动退出 1。教程还写过安装 cors,固定入口里并没有引入这个依赖,因此文章不能把“跨域设置”写成已经完成的功能。
更显眼的是 node_modules。固定树跟踪了 476 个依赖文件,而 .gitignore 只排除了 .DS_Store。当时为了让代码完整地进入仓库,连本可由锁文件重建的内容也一起提交了。仓库因此变大,依赖来源也变得难以审查。
接口本身同样相信输入。GET /get 不检查参数是否存在,POST /post 不限制字段和大小,两个所谓的登录路径只返回文字。端口无法通过环境变量修改,也没有统一错误处理、健康检查或关闭流程。
这些缺口不妨碍它作为一份练习成立。相反,它们让练习的范围变得清楚:我当时在学习 Express 如何接住请求、如何拆路由、如何返回文件,还没有进入一项服务长期运行所需要的那部分工作。
两年多以后再运行一次
2026 年 8 月 9 日,我在临时目录检出最后一条固定提交,用 Node.js 22.22.3 和 npm 10.9.8 重新安装依赖。npm ci 安装了 62 个包,服务随后在 8080 端口启动。
根页面可以打开,查询参数和 JSON 能按原样返回,/app/login 与 /admin/login 也得到各自的固定文本。最小路径仍然走得通。仓库里的测试则按原定义失败,因为它从未有过测试用例。
这次结果只属于 2026 年的复核。它不能反推 2023 年的 Vercel 部署成功,也不能说明代码适合今天的服务端。当前 Node 版本能够运行这几条路由,和一个服务具备校验、日志、测试、进程管理及恢复能力,是两件相距很远的事。
配置文件和线上结果之间
固定树同时保存了 package-lock.json 和被跟踪的 node_modules,README 里的 npm start 也没有对应脚本。端口仍固定为 8080,/get 与 /post 原样回送输入,两个名为登录的路由没有认证。这些缺口在最后一次提交后没有被补齐。
vercel.json 将所有路径交给 app.js,只能说明当时准备了一个部署入口。仓库没有预览地址、构建日志、线上响应或回滚记录,因此正文没有写成部署成功。
旧文章还谈过数据库迁移、反向代理和发布回滚。它们属于后来做其他项目时积累的经验,放进这份 2023 练习只会模糊时间。这个仓库当时没有数据库,也没有 Nginx;它处理的是 Express 的入口、路由和静态页。
练习停在原来的位置
四十二分钟的提交窗口没有证明我在那天学会了后端。它保存了一次学习动作:从一个入口文件开始,拆出两组路由,发出几次请求,再为部署准备一个配置文件。它也保存了同样具体的欠账:依赖进入 Git,脚本互相对不上,测试从未开始。
这次复核没有翻新旧仓库。路由还能响应;仓库没有 lint 脚本,test 仍是会主动退出 1 的占位脚本。最后一条提交仍停在 2023 年 12 月 21 日,作为一份练习记录,这个状态已经足够准确。
本文于 2026-08-09 根据公开仓库固定提交和一次隔离运行重新整理;运行结果只代表本次复核。