官网重建不是换皮。老站停留在 2023 年(Odoo 16),博客与文档已迁到宏斋,留下一批陈旧页面、失效入口和一台需要长期打补丁的服务器。这次重建的目标有三条:内容回到母公司该有的样子、后端只做最可靠的一件事、老 URL 全部有交代。
为什么不是"改造老站"
先看事实:老站库里有 27 条页面记录(13 个唯一 URL)、13 篇博客、若干商城/论坛/课程的模板遗留页面。其中博客与文档已在宏斋维护了新版;商城课程论坛从未真正运营。改造意味着继续维护一台只为遗留言页存在的 Odoo 实例——成本远高于重写,且方向上背道而驰:文档与产品内容属于宏斋,官网要回到"母公司品牌站 + 技术服务商站"的位置。
三个核心取舍:
- 静态内容进代码仓库:新闻/法务这类静态文章放在前端仓库(
content/blog/*.mdx),随代码评审与发版,不经过数据库。文章修订走 Pull Request,构建期校验格式,没有"后台编辑器改坏了线上"这一类问题。 - 后端只保留一件事:把询盘表单可靠地送进 CRM——字段白名单、限流、人机验证、幂等,一样不少(下文展开)。
- 文档不分家:产品文档只在宏斋维护一份,官网不复制——两个域名发同一批内容是自我竞争,搜索表现只会互相稀释。
老 URL 的逐项处置
迁移最怕的不是新站建得不好,而是老 URL 一批404把积累的访问与权重一起扔掉。我们对老站全部 64 个 URL 做了逐项清单,分三类处置:
| 分组 | 数量 | 处置 | 目标 |
|---|---|---|---|
| 首页、关于、联系、法务等 | 9 | 站内 301 | 新站同名或对应页 |
| ERP 产品词页(pricing、saas-erp 等) | 3 | 跨域 301 | 宏斋产品页(带 UTM) |
| 博客文章 | 13 | 跨域 301 逐条映射 | 宏斋博客同名 slug |
| 文档入口 | 1+ | 跨域 301 | 宏斋用户手册 |
| 模板遗留(商城/论坛/课程/成员) | 38 | 410 | 无承接价值,明确下线 |
博客那 13 条是逐条核对的:用只读接口从老站导出原文与 slug 后,与宏斋的文章逐一对照——12 条 slug 一致直接映射,1 条在迁移时改过标题,补一条单独映射。全部规则落在边缘 nginx 的一张 map 文件里(随前端仓库版本管理),旧站不关机,切换后观察两周,把 access log 里仍在命中的旧路径继续补进 map。
前端:构建期零后端依赖
新的前端是 Next.js 16 的 App Router 双语站。这一代和常见资料相比有几处硬差异,值得单独提醒:params 与 searchParams 是 Promise、middleware 更名为 proxy.ts——锁定小版本(16.3.8)后按安装版的官方文档施工,而不是凭记忆。
更关键的是构建与运行时的地址契约。我们把"页面不经后端渲染"当作硬约束:
- 新闻等静态内容构建期从仓库读取,不依赖任何运行时接口;
- 唯一需要后端的只有询盘接口,通过 Next 的 rewrites 代理到后端——而 rewrites 是构建期烤入的路由清单,所以镜像构建时后端地址必须是固定的容器 DNS,绝不能烤进任何主机相关地址;
- 验收里因此多了一条:后端完全不可达时,
docker build仍须成功——它证明构建期确实零依赖。
后端:一个小而完整的接口
后端收窄为一个自研模块,唯一对外写接口是询盘提交。设计清单(另一篇文章有完整展开):字段白名单(多一个字段即拒)、按 IP 每小时 20 次的限流、Cloudflare Turnstile 人机验证、提交键 + 内容哈希的幂等语义(重试同号、内容变化 409)、幂等并发由数据库唯一约束兜底、通知在落库之后异步发送且失败不影响用户成功。单号用序列生成可读编号(OSTN/年/月/序号),商务侧一眼可引用。
还有一条容易被忽略的:隐私抑制——线索落 CRM 后不触发第三方数据增强。隐私承诺写在政策页上是不够的,要落到代码行为里。
验收方式
交付标准不是"构建通过",而是一张实测矩阵:
- 类型检查、单元测试、生产构建全部干净;
- 后端不可达时构建成功;生产镜像独立启动后,CMS 读取与表单提交(经代理)分别实测;
- 询盘端到端:浏览器真实提交 → CRM 落档(姓名/电话/主题/来源页正确)→ 同键重试返回同号 → 限流第 21 次 429;
- 双语 × 明暗 × 320px 真实页面走查;
- 内容闸门:未确认内容在严格模式下直接阻断发布。
写到最后
重建一个官网真正的成本不在页面,而在决定每样东西"在哪、归谁、怎么下线"。把这三件事列清楚,技术选型反而是最简单的一步。
