第 10 章 · 前后端协作

全课收官:把前九章的零件装回真实世界的完整链路。前端不是孤岛,它的每个数据都来自后端(后端的每个字节又来自数据库,数据库课的链条)。本章讲清协作的四个基础设施:前后端分离的架构、REST API 的约定、跨域 CORS 的规则、身份认证的两种方案,最后用「一次点击的完整旅程」把全课程串成一个闭环。

10.1 前后端分离:两支团队,一份契约

老架构是服务端渲染:后端把 HTML 全拼好吐给浏览器,前端「切图仔」改模板。现代主流是分离:

浏览器(前端:SPA,第 8 章的框架应用)
   │  HTTP + JSON(第 2 章)
   ▼
后端 API 服务(Java/Spring、Node、Go……)
   │  SQL(数据库课)
   ▼
数据库

分离的收益:两支团队并行开发(契约先行:接口文档定好,前端 mock 数据先跑)、独立部署扩容、前端技能栈与后端解耦。代价:首屏要等 JS 拉完再渲染(SPA 白屏,第 6 章的问题),补救是 SSR 服务端渲染(本站 Next.js 就是:首屏由服务端出,后续交互前端接管,「查看源代码有完整内容」的原因,第 1 章埋的伏笔)。

10.2 REST:用 HTTP 本身表达操作

REST 是主流 API 风格,核心思想:URL 表示资源,HTTP 方法表示操作,状态码表示结果:

fetch("/api/users/1")                                          // GET:查
fetch("/api/users", { method: "POST", body: JSON.stringify(u) })  // POST:增
fetch("/api/users/1", { method: "PUT", body: JSON.stringify(u) }) // PUT:改
fetch("/api/users/1", { method: "DELETE" })                    // DELETE:删

方法语义表(计网课第 2 章的幂等性在此实用化):

方法语义幂等
GET读是(重复读无害)
POST创建否(重发两条资源)
PUT / PATCH整体 / 局部更新是
DELETE删除是

幂等性直接指导客户端重试策略:GET/PUT/DELETE 超时可放心重发,POST 超时重发前要想想(可能已经建过了,需要幂等键)。写接口的纪律:资源用复数名词(/users 不是 /getUser)、状态码别全 200(400 参数错、401 未登录、403 无权限、404 不存在、500 服务器错,计网课第 2 章的分类在前端调试里天天用)。

10.3 CORS:浏览器设的关卡

开发时的第一堵墙:本地 localhost:5173 请求 api.example.com,控制台红字「blocked by CORS policy」。同源策略(协议+域名+端口全同才算同源)是浏览器的安全机制,拦的是「evil.com 的页面偷偷带你的 Cookie 请求 bank.com」这类攻击(计网课第 8 章)。关键认知:这是浏览器行为,服务器永远收得到请求(所以 curl 不跨域,只有浏览器跨域),放行的开关在后端响应头:

Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST

流程分两类:简单请求直接发,浏览器看响应头决定给不给 JS 读结果;预检请求(带自定义头如 Authorization、或非简单方法时)先发 OPTIONS 问「允许吗」,拿到许可才发真的。开发期的正统解法是 Vite 代理(第 9 章):server.proxy 把 /api 转发给后端,同源问题消失(代理是服务器行为,不受同源限制)。CORS 不是「报错修掉」的东西,理解「它防的是 CSRF 类攻击」后,生产环境正确配后端 CORS、开发环境走代理,才是完整答案。

10.4 鉴权:你是谁,凭据怎么带

HTTP 无状态(计网课第 2 章),每次请求都得自证身份,两大方案:

Cookie + SessionToken(JWT)
凭据存放浏览器自动带 Cookie前端手动放 Authorization 头
状态在哪服务端存 session(可随时吊销)无状态:令牌自包含,签名防篡改
跨域受限(Cookie 的 SameSite)天然适配(手动带就行)
吊销删 session 立即生效难(等过期或黑名单)
GET /api/me
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.xxxx

JWT 三段式(头.载荷.签名),载荷里明文放着用户 ID 和过期时间(JWT 不加密,别放敏感信息,只是签名防改)。选型口径:传统多页应用/同族域名,Cookie+Session 简单可靠;前后端分离 + 多端(App 也要用同一套 API),JWT 顺手。共同的安全底线:全程 HTTPS(计网课第 8 章),否则凭据裸奔。

10.5 一次点击的完整旅程(全课程闭环)

用户在页面上点「提交订单」,到屏幕更新,完整走一遍,每一步标注它属于本站哪门课:

① 点击按钮 → 事件监听器触发          [前端 05 事件]
② fetch 发请求,带 JWT              [前端 07 异步 / 10 本章]
③ DNS → TCP → TLS → HTTP           [计网 02~04]
④ 后端验签 → 业务逻辑 → SQL 事务     [数据库 07 事务]
⑤ 数据库 B+ 树查行,返回 JSON        [数据库 09 索引]
⑥ 响应回程,浏览器收 JSON            [计网 02]
⑦ setState 更新状态,框架 diff       [前端 08]
⑧ 虚拟 DOM 提交真 DOM,只重绘局部    [前端 06 渲染流水线]
⑨ 像素上屏,用户看到「下单成功」

九步,九门课的知识各就各位。这门 wiki 课程的初衷就在这:知识不是九个孤岛,是一次点击里的九个舞台。接下来可以往深走(任选一门课的进阶书单),也可以往宽走(把这门 wiki 部署上线,亲手走一遍 13.4 的流水线)。

常见错误

  • CORS 报错狂查前端代码。它是后端响应头的事;先 curl 后端接口确认服务本身通,再检查后端 CORS 配置和开发代理。
  • POST 幂等坑。网络重试导致重复下单;支付/下单类接口服务端必须做幂等键(数据库课第 7 章的并发控制)。
  • JWT 放 localStorage 无脑存。XSS(第 5 章)能偷走它;敏感应用用 HttpOnly Cookie(前端读不到,JS 偷不走)配合后端 CORS 凭据配置。
  • 状态码全 200 + body 里 code 字段。浏览器、监控、缓存层全瞎;让 HTTP 语义干活,别造私有协议。

练习

  1. 动手:走完一次真实协作:用 Vite 起前端,写一个十几行的 Node/Express(或 Java)接口返回 JSON,亲历一次 CORS 报错,然后分别用「后端加 CORS 头」和「Vite 代理」两种方式解决。
  2. 动手:DevTools Network 面板解剖一次登录:看预检 OPTIONS(如有)、Cookie 或 Authorization 头、Set-Cookie 响应,对照 10.4 画出你的鉴权方案图。
  3. 综合:给第 7 章的 TodoList 接上真实后端(哪怕是最简 REST:GET/POST/DELETE /api/todos),处理加载态、失败重试、乐观更新,把「一次点击的旅程」自己走通一遍。
  4. 思考:全课程复盘:从 HTML 一行标签到「一次点击的九步旅程」,哪一步的知识最出乎你的意料?哪两门课的交叉点你觉得最值得再深挖?把这个答案当成你下一步的学习地图。