← 学习路线

拆开一个 AI 做出来的网站

AI 帮你做出来的网站,由哪几部分组成、各自住在哪?出了问题,该去哪一层找?

课型:概念·约 20 分钟·6 个术语

先看出事的那一刻

2026 年 9 月 27 日,这个网站刚从单页应用迁到 Astro(第 4 课讲的就是那次迁移)。迁移分支推上去以后,这次提交上挂着两个检查结果:Vercel 显示部署成功,Cloudflare Pages 显示构建失败。

第一反应是:Cloudflare 是哪来的?网站不是在 Vercel 上吗?仓库里有 vercel.json,AI 刚写好的 README 也写着"推送 main,Vercel 自动部署"。直到用 curl -I 看了一眼线上的响应头:server: cloudflare,没有 Vercel 会留下的 x-vercel-id。真正的线上,是那个构建失败的平台。

这节课要回答的是:AI 帮你做出来的网站,由哪几部分组成、各自住在哪?出了问题,该去哪一层找?

装备几个词

为什么要懂

AI 替你做了

一句“帮我做个带登录的学习网站”,AI 就能写好页面、起好服务、建好数据库,再顺手接上两三个托管平台。

留给你的

知道每一部分住在哪、谁连着谁。出了问题,先判断是哪一层坏了,才知道该让 AI 改哪里。这张图 AI 不会主动画给你。

不懂的代价

在错误的那一层反复修:改了半天页面,问题其实在托管平台;看着一个平台的“部署成功”就合并上线,真正的线上却在另一个平台,还带着一次失败的构建。

一家餐厅的五个部分

把一个网站想成一家餐厅:

  • 前端是大堂:菜单、桌椅、服务员的招呼,客人看得到、摸得着的都在这里。
  • 后端是后厨:客人看不见,每一道菜都在这里做,菜谱和进货渠道也只放在这里。
  • 数据库是仓库和账本:原料和每一笔账都记在这里,厨师换班也不会丢。
  • 接口是传菜窗口:大堂按固定格式把单子递进去,后厨按固定格式把菜递出来。
  • 托管平台是商场出租的店面,水电、保安、客流归商场管;域名是挂在门口的招牌。

不是每家店都五样俱全。只卖便当的小窗口没有后厨也能开张:菜在中央厨房做好(构建时生成),窗口只负责递出去。这就是纯静态的网站。

两个真实的网站,拆开看

这个网站和它的兄弟项目 E2E Review 都是 AI 做的,拆开来却是两张完全不同的图:

这个网站E2E Review
前端Astro 在构建时生成的静态页面React 写的单页应用
后端没有Node + Hono 写的服务:登录、学习进度、AI 导师
数据库没有,文章就是仓库里的文件Postgres:账号、对话、进度、用量
接口没有十二个 /api/ 开头的地址
托管Cloudflare Pages(仓库还连着一个用不上的 Vercel 项目)前端在 Cloudflare Pages,后端和数据库在 Railway
域名www.felixwithai.come2e.felixwithai.com(现已并入本站 /e2e)
第三方没有大模型接口,密钥只放在后端

同样一句"帮我做个网站",左边那张图几乎不用维护;右边每多一格,就多一份账单、一个可能出错的地方、一把要保管的钥匙。

所以遇到问题,先对着这张图缩小范围。比如 E2E Review 的页面和术语都正常,唯独导师提示"暂时不可用":术语也是后端给的,术语正常说明后端活着,问题最可能在后端到大模型接口的那一段。

深潜怎么确认网站真正托管在哪+

网站托管在哪,看的不是仓库里有哪个平台的配置文件,而是域名最终指向谁。最直接的证据是线上服务器自己写的响应头:

curl -sI https://你的域名 | grep -iE "^(server|cf-ray|x-vercel-id)"

各家平台都会留下特征:Cloudflare 有 server: cloudflare 和 cf-ray,Vercel 有 x-vercel-id。

也可以查 DNS,但要注意:如果域名经过 Cloudflare 代理(后台显示为橙色云朵),查询结果只会是 Cloudflare 的地址,看不到背后是哪个平台。这时要到 DNS 后台看那条记录指向哪里。本站的 space 记录指向 web-6eg.pages.dev,一看就是 Cloudflare Pages。

深潜一个仓库,为什么会连着两个平台+

托管平台接入代码仓库只要点几下授权,之后每次推送,它都会自动构建、部署一次。本站的仓库 3 月接上了 Vercel,域名却一直指向 Cloudflare Pages。Vercel 的连接没有断开,每次推送照样部署,至今已部署了几十次,没有一个访客看得到。

多余的连接不只浪费构建资源,还会误导人:它发出的"部署成功",和真正线上的通知看起来一模一样。接平台容易,想着断开的人很少。

找茬

下面是两个项目里 AI 写的部署说明,都来自真实提交(节选)。对照这组事实,找出和事实对不上的句子:本站由 Cloudflare Pages 提供,`vercel.json` 只对一个没人访问的 Vercel 项目生效;E2E Review 的后端当时跑在 Railway 的容器里,数据库是 Postgres,自定义域名已经改由 Cloudflare 接入。

这段 Markdown / 注释 里埋了 6 处问题。点击你觉得有问题的行,至少找出 3 处再揭晓。

查看代码与答案(6 处问题)
 1  # 本站 README.md(迁移时 AI 写的部署说明,节选)
 2  - 配置在 astro.config.mjs:全静态输出、build.format: "file",配合 vercel.json 的 cleanUrls 保持旧站网址不变。
 3  Vercel 项目 felix-website,连接本仓库:推 main 部署生产,推其他分支生成预览地址。
 4  
 5  # 本站 src/pages/404.astro(文件头注释)
 6   * pos:    路由兜底;Vercel 对不存在的路径返回它
 7  
 8  # E2E Review 的 docs/ARCHITECTURE.md(节选)
 9  Node 服务 (Hono, 单进程, VPS)
10    ├─ 内容层: content/*.json(构建时从 md 语料编译,不进前端 bundle)
11    ├─ 数据层: SQLite (users / sessions / progress / events)
12  React + Vite SPA,使用 hash 路由保证 Cloudflare Pages 静态托管下的可分享页面状态。
13  
14  # E2E Review 的 README.md(节选)
15  | 自定义域名 e2e.felixwithai.com | ⏳ DNS 已配好,等 Railway 签发证书 |
  • 第 2 行 · 中危 · 线上环境根本不读这个文件:vercel.json 只对 Vercel 生效,而线上网站由 Cloudflare Pages 提供。旧网址能保持,靠的是 Cloudflare Pages 自己把 /x 对应到 x.html。照这句话去改 vercel.json,线上不会有任何变化。 该问的话:这个配置文件,线上环境真的会读吗?
  • 第 3 行 · 高危 · 把没人访问的平台写成了生产环境:照这句话,只要 Vercel 的检查变绿就可以合并。可同一次提交上,真正的生产环境 Cloudflare Pages 构建失败了。 该问的话:线上域名现在由哪个平台提供?给我一条命令确认。
  • 第 6 行 · 低危 · 误会已经写进了代码注释:说明文档里的误会,会顺着 AI 的手写进代码注释。下一个读代码的人,或者下一个 AI,会接着相信它。更正时要把这些地方一起找出来。 该问的话:项目里还有哪些地方提到了 Vercel?
  • 第 9 行 · 中危 · 后端从来不在 VPS 上:后端被打包成容器,跑在 Railway 上。照着这份文档去服务器上找日志、改配置,会发现根本没有这台机器。 该问的话:后端现在具体跑在哪里?它的日志在哪看?
  • 第 11 行 · 中危 · 数据库早就换了:前一天,数据层就从 SQLite 换成了 Railway 上的 Postgres,文档没跟上。照着它去备份数据,备份的是一个已经不用的文件。 该问的话:线上的数据存在哪个数据库里?怎么备份?
  • 第 15 行 · 低危 · 写的是已经过去的状态:这一行写下时,自定义域名早已改由 Cloudflare 接入,不再等 Railway 签发证书。过期的状态会让人以为问题还没解决,再去排查一遍。 该问的话:这份 README 里的线上状态,最后一次核对是什么时候?

快测

1. 用 curl -sI 请求一个网站,响应头里有 server: cloudflare 和 cf-ray,没有 x-vercel-id。仓库里却有一个 vercel.json。网站最可能由谁提供?

查看选项与答案
  • A. Cloudflare,这两个响应头是它的特征(正确)——响应头是线上服务器自己写的,比仓库里的任何配置和说明都可靠。这里有 server: cloudflare 和 cf-ray,没有 Vercel 会留下的 x-vercel-id。
  • B. Vercel,仓库里有它专用的配置文件,托管在它那里——仓库里有 vercel.json,那网站肯定在 Vercel 上。可配置文件只说明仓库和 Vercel 有过关系;线上是谁,要看域名指向谁、响应头是谁写的。
  • C. 两个平台都在服务,每位访客随机落在其中一个——两个平台都连着仓库、都在部署,那就都在接待访客。可一个域名同一时刻只会指向一个地方,另一个平台部署得再勤,也没有访客看得到。

确认托管方,看响应头和 DNS,不看配置文件和文档。

2. 你想给纯静态的博客加一个“问 AI”的功能,要调用大模型接口,接口需要密钥。密钥应该放在哪?

查看选项与答案
  • A. 存进数据库,前端每次调用前从数据库读出来——数据库总比代码里安全。可前端要能读出密钥,访客的浏览器就能读出密钥;数据库也要靠后端去读,让前端直接连数据库,等于把仓库钥匙交给了访客。
  • B. 写进前端代码,再把仓库设为私有,就不会泄露——仓库设成私有,密钥就安全了。可私有的只是源码仓库;前端代码会完整下载到每个访客的浏览器里,密钥照样在里面,任何人都能拿去用,费用算你的。
  • C. 放在后端或无服务器函数里,前端只调用自己的接口(正确)——密钥只能待在访客看不到的地方。前端把问题交给你自己的接口,由后端带着密钥去调大模型,访客拿到的只有回答。

判断一样东西该放在哪一层,先问:它能不能让访客看到?

3. E2E Review 的页面和术语都正常,唯独导师提示“暂时不可用”。最该先查哪一部分?

查看选项与答案
  • A. 后端去调用大模型接口的那一段(正确)——术语也是后端给的,术语正常说明后端活着。只有导师不行,问题最可能在后端到大模型接口之间。
  • B. 前端所在的托管平台和它的部署状态——网站出了问题,先怀疑托管平台。可页面能正常打开,说明前端和托管平台都是活的;托管出故障,整个网站都会受影响,不会只有导师不行。
  • C. 整个后端进程,看它是不是已经挂掉了——导师用不了,那就是后端挂了。可术语也是后端给的,术语正常说明后端活着;只有导师不行,问题更可能出在后端到大模型接口的那一段。

先看哪些部分正常、哪些不正常,再对着结构图缩小到出问题的那一段。

判断时刻

你的博客是纯静态网站,托管在 Cloudflare Pages。你想加一个“问 AI”的功能:读者输入问题,调用大模型回答。你让 AI 实现,它给了三个方案。

你会选哪一个?

三个选项各自的代价
  • A. 前端直接调用大模型接口,密钥写在前端代码里——考察安全与成本:最快,也最危险。密钥会随页面下载到每个访客的浏览器里,任何人都能拿去调用,账单算你的。这不是“以后再优化”的问题,上线那一刻就暴露了。
  • B. 加一个无服务器函数做中转,密钥放在它的环境变量里——考察改动成本与控制力:改动小,不用常驻服务器,密钥也不出后端。代价是限流、防刷要自己写在函数里;访客一多,调用次数和费用都要有上限。
  • C. 单独起一个后端服务加数据库,做账号和用量统计——考察完整度与维护负担:最完整:能登录,能记录每个人用了多少,能按人限额。代价是多一个平台、一份账单、一套要维护的服务。E2E Review 走的就是这条路:为了导师和学习进度,它多出了一个后端、一个数据库和一整套额度护栏。

三个方案都能跑起来,差别在于密钥放在哪一层、谁来挡住滥用、你愿意多维护几个部分。A 是唯一不能选的:它把本该待在后厨的东西,摆到了大堂上。

带走

下次让 AI 做这件事时,问它

  1. 这个项目由哪几部分组成?每部分的代码在哪个目录、部署在哪个平台、用哪个地址访问?
  2. 线上域名现在由哪个平台提供?这个仓库还连着哪些平台,它们的部署会不会被误当成线上?
  3. 哪些数据需要长期保存?存在哪里,重新部署以后会不会丢?
  4. 前端代码里有没有任何密钥,或者只该让后端知道的地址?

自己验证

  • curl -sI 你的网址:看 server、cf-ray、x-vercel-id 这类响应头,确认真正的托管方。
  • 在代码仓库的提交记录上看检查结果:每个平台各占一栏,分清哪一栏才是线上。
  • 打开浏览器开发者工具的“网络”面板,看页面向哪些地址发了请求:它们就是这个网站依赖的后端和第三方服务。

先画出网站住在哪、谁连着谁,再决定让 AI 改哪里。