Skip to content

前后端联调

前端页面和后端接口各自跑通了,合到一起时大概率遇到各种问题:跨域报错、登录后 Token 带不上、字段名对不上、请求发了但数据不对。这些联调时常见的坑和调试方法,集中过一遍。

一、CORS——跨域请求被拦

前端 localhost:5173 调后端 localhost:8000,浏览器控制台报:

text
Access to fetch at 'http://localhost:8000/api/assets' from origin 'http://localhost:5173'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header

原因:端口不一样算跨域,浏览器要求后端在响应头里明确说"我允许 localhost:5173 访问"。后端 CORS 中间件配了 allow_origins=["http://localhost:5173"] 才会带这个头。

后端确认配置(17 篇讲过):

python
# backend/app/main.py
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173"],  # 前端开发服务器
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

排查方法:浏览器 Network 面板,找到被拦的请求,看 Response Headers 里有没有 Access-Control-Allow-Origin。没有就是后端没配 CORS,或者 allow_origins 里没写前端地址。

二、Token 传递的完整链路

登录后前端拿到 Token,后续请求要带上。整个链路:

每个环节出问题的表现

环节表现排查
登录接口返回没 Token前端存不进去,后续全 401后端日志看 /login 有没有报错
Token 没存进 localStorageNetwork 看请求头没 Authorization浏览器 Console 执行 localStorage.getItem("access_token")
Token 存了但请求没带Network 看请求头没 Authorization检查 request 函数有没有读 Token 放进 headers
Token 带了但后端不认401 UnauthorizedToken 过期、SECRET_KEY 前后端不一致、Token 格式错

最有效的排查方法:浏览器 F12 → Network 面板 → 点失败的请求 → 看 Request Headers 里 Authorization 字段。有就是带了,没有就是 request 函数有问题。带了还是 401,就是 Token 本身的问题。

三、字段名不一致

后端返回 {"hostname": "web-01"},前端读 asset.host_name(下划线位置不一样),页面显示空白。

这种问题不会报错——接口正常返回 200,但页面没数据。最隐蔽的一类 bug。

排查方法:Network 面板看 Response——后端实际返回的 JSON 字段名是什么,跟前端代码里用的字段名逐个对比。

js
// 后端返回
{"id": 1, "hostname": "web-01", "ip": "192.168.1.10"}

// 前端代码
<td>{{ asset.hostname }}</td>   // ✅ 对上了
<td>{{ asset.host_name }}</td>  // ❌ 多了下划线,显示空白

预防:后端 Schema 和前端 TypeScript 类型定义保持一致(如果用了 TypeScript)。没用 TypeScript 就靠仔细对照——或在前端 API 函数里做一层字段映射。

四、POST 请求体格式

前端发 POST 请求,后端收到的请求体是空的或格式不对:

js
// 常见错误:没设 Content-Type,或 body 没转 JSON
fetch("/api/assets", {
  method: "POST",
  body: { hostname: "web-01" },  // ❌ 直接传对象,fetch 不认
});

// 正确
fetch("/api/assets", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ hostname: "web-01" }),  // ✅ 转成 JSON 字符串
});

fetchbody 只接受字符串。JS 对象要 JSON.stringify 转成 JSON 字符串,同时设 Content-Type: application/json 告诉后端"我发的是 JSON"。06 篇封装的 request 函数已经处理了这两件事,用它就不会踩这个坑。

五、登录接口的特殊格式

FastAPI 的 OAuth2PasswordBearer 默认从表单格式application/x-www-form-urlencoded)拿用户名密码,不是 JSON。前端登录请求要发表单格式:

js
// ❌ JSON 格式——FastAPI 的 OAuth2 表单不认
fetch("/api/users/login", {
  body: JSON.stringify({ username: "admin", password: "123" }),
});

// ✅ 表单格式
fetch("/api/users/login", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: "username=admin&password=123",
});

这个不一致很容易踩——后端用了 OAuth2PasswordBearer,但前端习惯性发 JSON。要么前端改表单格式,要么后端用 Pydantic 模型接收 JSON 请求体(不用 OAuth2 标准表单)。24 篇的登录 API 封装里已经用了表单格式。

六、调试工具

工具用途
浏览器 F12 Network看每个请求的 URL、方法、请求头、响应体、状态码
浏览器 Console看 JS 报错、打印变量值
后端日志看请求有没有到后端、后端处理有没有报错
curl不走前端,直接测后端接口——排除前端问题
FastAPI /docs交互式文档,直接在页面上测每个接口

联调时最常用的排查路径:先看 Network 面板(请求发了没?状态码多少?响应体长啥样?)→ 再看 Console(前端 JS 有没有报错?)→ 最后看后端日志(请求到后端了没?后端有没有异常?)。沿着这条线查,绝大多数联调问题都能定位。

七、联调检查清单

前后端都跑起来后,按这个清单逐项验证:

  • [ ] 前端能访问后端(Network 看到请求发出去了,没有 CORS 报错)
  • [ ] 登录能拿到 Token(Network 看 /login 返回里有 access_token
  • [ ] Token 存进了 localStorage(Console 执行 localStorage.getItem("access_token")
  • [ ] 后续请求带了 Authorization 头(Network 看请求头)
  • [ ] 列表页能加载到数据(Network 看 /assets 返回 200,有数据)
  • [ ] 创建操作成功(Network 看 POST 返回 200,数据库里有新记录)
  • [ ] 删除操作成功(Network 看 DELETE 返回 200,列表刷新后记录消失)
  • [ ] 事件日志有记录(每次创建/删除后,事件页能看到对应记录)

全通过,前后端就联调完成了。后面几篇做任务调度、Docker 打包、部署上线。