全栈工程课 · 一个相册系统的上线之路
课程平台Chapter 8 · 前后端联调

CHAPTER 8 · FRONTEND INTEGRATION

08

后端接口在 Postman 中返回 200,为什么 React 页面还是拿不到数据?

Postman 成功只能说明后端接口在某个请求条件下可用。浏览器页面是否成功,还取决于请求地址、代理、Token、字段结构和前端状态处理。

三个常见现象

接口能通,不等于页面能用。

01

Postman 请求成功
React 请求失败

02

登录成功并拿到 Token
查询相册仍然返回 401

03

前端运行在 5173
后端运行在 8080
浏览器提示跨域

先问清楚这些问题

Postman 成功能证明什么?

浏览器和 Postman 有什么不同?

前端请求实际发到了哪里?

Token 是否正确携带?

前端读取的字段和后端返回的一致吗?

AI 生成的代码能运行,结构就一定合理吗?

联调成功 = 接口正确 + 请求正确 + 代理正确 + 身份正确 + 数据结构正确

第一步

先用 Postman 隔离后端问题。

如果 Postman 都不能正确调用接口,先不要急着改 React。前端页面只会把问题变得更分散。

登录接口

  • 请求地址是否正确
  • 是否使用 POST
  • 请求体是否是 JSON
  • 成功状态码是什么
  • 错误密码返回什么
  • 响应里 Token 字段叫什么

相册列表接口

  • 是否携带 Authorization
  • 是否使用 Bearer 格式
  • 分页参数是否正确
  • 空列表返回 [] 还是 null
  • Token 无效时返回什么
  • 真实字段名是否记录下来
先验证后端记录真实响应再生成前端对比浏览器请求

AI 任务描述

让 AI 写前端前,先给它完整接口契约。

给 AI 的任务描述模板
请使用 React、Vite 和 TypeScript,为现有相册后端开发前端页面。

后端接口:
1. POST /api/login
2. GET /api/my/albums?page=1&pageSize=20

统一响应结构:
{
  "code": "OK",
  "message": "success",
  "data": {}
}

要求:
1. 登录成功后保存 accessToken。
2. 请求相册接口时携带 Bearer Token。
3. 使用 TypeScript,禁止使用 any。
4. API 请求不能直接散落在页面组件中。
5. 页面必须处理加载、空数据和错误状态。
6. 所有后端请求使用 /api 相对路径。
7. 不要在代码中写死 localhost:8080。
8. 不要修改 Go 服务端的跨域配置。

AI 生成代码的质量,很大程度取决于输入是否包含完整接口契约和工程约束。不要只说“帮我做一个相册前端”。

项目结构

前后端可以放在同一个练习项目里,但职责要分清。

album-system/
album-system/
├── backend/
│   ├── cmd/
│   ├── internal/
│   ├── migrations/
│   └── go.mod
├── frontend/
│   ├── src/
│   ├── package.json
│   ├── tsconfig.json
│   └── vite.config.ts
└── README.md

这样做的好处是:一次打开完整项目,便于对照前后端接口,也便于 AI 同时读取两侧代码。正式项目中,前端和后端可能会拆成不同仓库、不同构建方式和不同发布流程。

frontend/src/
frontend/src/
├── api/
│   ├── request.ts
│   ├── auth.ts
│   └── albums.ts
├── components/
│   ├── AlbumCard.tsx
│   ├── Loading.tsx
│   └── ErrorMessage.tsx
├── pages/
│   ├── LoginPage.tsx
│   └── AlbumListPage.tsx
├── types/
│   ├── api.ts
│   ├── auth.ts
│   └── album.ts
├── App.tsx
└── main.tsx

不要把登录、请求、Token、相册列表和错误处理全部写进 App.tsx

TypeScript 审查

TypeScript 类型必须对齐真实响应。

AI 定义

items: Album[]

后端实际返回

items: null

检查点结论原因

是否把类型改成 Album[] | null

先别急

如果接口约定空列表返回数组,应优先修复后端响应。

是否大量使用 any

不要

any 会让类型检查失去价值,也会掩盖字段层级错误。

时间字段是否先用 string 接收

可以

JSON 返回的是字符串,前端需要格式化时再转换。

接口设计约定为空数组时,应修复后端,不要为了兼容错误响应不断放宽前端类型。

请求封装

请求逻辑不要散落在每个页面里。

错误示例

fetch("http://localhost:8080/api/my/albums")
问题判断解释

写死后端地址

错误

换环境就要改代码,也会绕过开发代理。

直接请求 8080

错误

浏览器会发起跨域请求,问题不再经过 Vite Proxy。

统一使用 /api

推荐

开发阶段交给 Vite Proxy 转发,上线阶段交给统一入口处理。

Vite Proxy

开发阶段,让浏览器只请求 5173。

frontend/vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],

  server: {
    proxy: {
      "/api": {
        target: "http://localhost:8080",
        changeOrigin: true,
      },
    },
  },
});
浏览器请求
localhost:5173/api/my/albums
Vite 开发服务器 ↓ 代理转发 Go 后端
localhost:8080/api/my/albums

前端代码统一使用 /api。修改 vite.config.ts 后需要重启 Vite。Vite Proxy 只存在于开发环境,不是正式上线方案。

不要这样解决联调

不要为了方便,直接开放 Go 服务端任意跨域。

本章约定

React → /api

Vite Proxy

Go 后端

不要这样做

React
↓ 直接跨域
Go 后端允许所有 Origin

不要把它当作联调方案

Access-Control-Allow-Origin: *

开放跨域不等于绕过 JWT,但不能把允许任意来源当作解决联调问题的方法。CORS 不能替代认证和权限控制,非浏览器客户端也不会受到浏览器 CORS 的保护。

Network 排错

页面失败时,先看浏览器到底发了什么请求。

Request URLhttp://localhost:5173/api/my/albums
Request MethodGET
Status Code401
AuthorizationBearer ...?

这个请求返回 401,优先看身份凭证。

先检查 Authorization 请求头是否存在,格式是否是 Bearer <token>,Token 是否过期。不要先去改 MySQL 索引、CSS 或 Vite 主题配置。

请求是否发出地址是否正确方法是否正确状态码是多少Token 是否携带后端返回了什么前端读取字段是否正确

问题定位

Postman 成功,React 出现跨域错误,先改哪里?

开发阶段优先检查请求路径和 Vite Proxy。

如果 Postman 能调通,而 React 页面出现跨域错误,通常不是 MySQL、JWT 算法或页面样式的问题。先确认前端是否使用 /api 相对路径,以及 vite.config.ts 是否正确代理到 Go 后端。

AI 代码审查

能跑起来之后,还要看结构和边界。

项目结构

API 请求是否与页面组件分离?类型是否集中定义?是否把全部代码写进 App.tsx?组件是否拆分过度?

TypeScript

是否使用 any?请求和响应是否有类型?是否存在大量无依据类型断言?类型是否符合真实响应?

请求逻辑

是否使用 /api?是否统一携带 Token?是否判断 HTTP 状态码?是否处理加载、空数据和错误状态?

安全与配置

是否写死后端地址?是否把 JWT Secret 写入前端?是否要求修改 Go CORS?是否添加了任意跨域?

bad_request.ts
fetch("http://localhost:8080/api/my/albums");

这行代码至少包含四个问题:写死环境地址、绕过 Vite Proxy、可能触发浏览器跨域、没有经过统一请求封装。

本章总结

  1. React 开发前,应先用 Postman 验证后端接口。
  2. Postman 成功不代表浏览器页面一定成功。
  3. 前端页面可以由 AI 快速生成,但接口契约和工程约束必须给清楚。
  4. 项目结构用于分离页面、组件、API 和类型。
  5. TypeScript 不能代替真实网络响应验证。
  6. 前端请求统一使用 /api 相对路径。
  7. 开发阶段由 Vite Proxy 转发到 Go 服务。
  8. 不要通过开放任意跨域解决联调问题。
  9. Network 面板是前后端联调最重要的排查工具之一。
  10. 当前前后端放在同一个练习项目里,是为了方便本地开发和对照接口。
Vite Proxy 只存在于开发环境,正式上线后谁来转发 /api
下一章进入前后端构建、Nginx 和正式发布链路。