跳转到内容

HTTP 与 API 基础:前端和后端怎么对话

完成时间:约 25 分钟。读完后你能看懂浏览器和后端之间传来传去的请求和响应,不再觉得它们是黑魔法。

还记得 CS 基础篇里的类比吗?API = 服务员递给厨房的点菜单。那篇讲的是概念,这篇讲的是实操——点菜单长什么样、服务员怎么跑腿、厨房怎么回话。


你(前端)坐在餐厅里点菜,服务员拿着一张点菜单(HTTP 请求)跑到厨房(后端),厨房做好后把菜端回来(HTTP 响应)。

这个”点菜 → 上菜”的过程,就是一次 HTTP 请求/响应

每次你在网页上点击一个按钮、提交一个表单、刷新一个页面,浏览器都在背后完成这个过程——组装一张点菜单,发给后端,等后端回话。


开发时,前端和后端都跑在你自己的电脑上,不在互联网上。

  • localhost = “这台电脑自己”。你在浏览器里输入 localhost,访问的就是你面前这台机器,不是某个远方的服务器。
  • 端口 = 一台电脑上不同程序的”门牌号”。一台电脑可以同时跑好几个程序,每个程序占一个端口,互不冲突。

本课程里常见的三个端口:

地址住着谁干什么
localhost:8080后端程序(Go/Gin 服务器)处理 API 请求
localhost:5173前端程序(Vite 开发服务器)展示网页界面
localhost:5432数据库(PostgreSQL)存储数据

类比:localhost 是一栋大楼,端口是房间号。 8080 房间住着后端,5173 房间住着前端,5432 房间住着数据库。你要找谁,就敲谁的门。

为什么前端能请求 /api/users 而不用写 localhost:8080

Section titled “为什么前端能请求 /api/users 而不用写 localhost:8080?”

因为 Vite 开发服务器做了”代理”——它看到以 /api 开头的请求,会自动转发给 localhost:8080。你不用操心这个,知道有这回事就行。


URL 就是一个地址,告诉浏览器”去哪里找东西”。拆开看:

https://api.example.com:8080/api/users?role=admin&page=1
└─协议──┘└──域名──────────┘└端口┘└──路径───┘└───查询参数────┘
部分说明类比
协议https 表示加密传输点菜单是密封信封还是明信片
域名服务器的名字餐厅的招牌地址
端口程序的门牌号(可省略)大楼的房间号
路径具体要什么资源菜单上的菜名
查询参数附加条件,? 开头,& 分隔”少辣、加葱”

开发时用 localhost,上线后换成域名(比如 api.example.com),其他部分不变。


每次前端发请求,都由这 4 样东西组成:

要素说明示例
方法你要做什么GET(查)POST(增)PUT(改)DELETE(删)
URL对谁做/api/users/1
Headers附加信息Content-Type, Authorization(JWT token)
Body发送的数据POST/PUT 才有,通常是 JSON

类比:一张点菜单。 方法 = 你要点菜还是退菜;URL = 哪道菜;Headers = 备注(会员卡号、过敏信息);Body = 具体的菜品详情。


1. GET — 查询数据(翻菜单看看有什么)

Section titled “1. GET — 查询数据(翻菜单看看有什么)”

只是”看一下”,不修改任何东西。没有 Body——你翻菜单不需要交任何材料。

Terminal window
# curl 示例
curl http://localhost:8080/api/users
// 前端 fetch 示例
fetch('/api/users')

2. POST — 创建数据(下单点菜)

Section titled “2. POST — 创建数据(下单点菜)”

提交一份新数据给后端。Body 里带着要创建的内容。

Terminal window
# curl 示例
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name":"小明","email":"xiaoming@example.com"}' \
http://localhost:8080/api/users
// 前端 fetch 示例
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: '小明', email: 'xiaoming@example.com' })
})

用新数据整体替换旧数据。URL 里指定要改哪一条,Body 里放新内容。

Terminal window
# curl 示例
curl -X PUT \
-H "Content-Type: application/json" \
-d '{"name":"小红","email":"xiaohong@example.com"}' \
http://localhost:8080/api/users/1
// 前端 fetch 示例
fetch('/api/users/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: '小红', email: 'xiaohong@example.com' })
})

告诉后端”把这条数据删了”。通常没有 Body——你退菜只需要说菜名,不需要再交一份材料。

Terminal window
# curl 示例
curl -X DELETE http://localhost:8080/api/users/1
// 前端 fetch 示例
fetch('/api/users/1', { method: 'DELETE' })

5. PATCH — 局部更新(加辣 / 少盐)

Section titled “5. PATCH — 局部更新(加辣 / 少盐)”

和 PUT 的区别:PUT 是整道菜换掉,PATCH 是只改一个细节(比如只改名字,其他字段不动)。

Terminal window
# curl 示例:只更新名字,其他字段不变
curl -X PATCH \
-H "Content-Type: application/json" \
-d '{"name":"小刚"}' \
http://localhost:8080/api/users/1

后端收到请求后,会返回一个响应。响应也由 3 样东西组成:

要素说明类比
状态码结果如何(成功/失败)服务员回来说”菜好了”还是”卖完了”
Headers响应的附加信息小票上的时间戳、备注
Body返回的数据(通常是 JSON)端上来的菜本身

状态码是一个三位数字,告诉你这次请求的结果。不用全背,认识下面这些就够了:

状态码含义类比
200 OK请求成功,返回数据你点的菜上了
201 Created创建成功新菜下单成功,厨房确认了
204 No Content操作成功,但没有返回数据退菜成功,服务员点点头走了
状态码含义类比
301 Moved Permanently资源永久搬走了餐厅搬家了,门口贴了新地址
302 Found资源临时在另一个地方今天在隔壁临时摊位营业

了解即可,日常开发很少需要手动处理这两个。

4xx — 客户端错误(你这边的问题)

Section titled “4xx — 客户端错误(你这边的问题)”
状态码含义类比
400 Bad Request请求格式不对点菜单写得乱七八糟,厨房看不懂
401 Unauthorized没有登录 / token 过期你没出示会员卡,被拒之门外
403 Forbidden登录了但没权限你是普通会员,这道菜只有 VIP 能点
404 Not Found请求的资源不存在你点了一道菜单上没有的菜
422 Unprocessable Entity格式对了但内容不合法点菜单格式没问题,但”冰淇淋要全熟”这种要求做不到

5xx — 服务端错误(后端的问题)

Section titled “5xx — 服务端错误(后端的问题)”
状态码含义类比
500 Internal Server Error服务器内部出错厨房着火了
502 Bad Gateway网关收到了无效响应外卖平台联系不上餐厅
503 Service Unavailable服务暂时不可用餐厅今天休息

REST 不是一个软件或工具,而是一种设计接口的约定——大家都这么写,方便理解和协作。

核心规则很简单:URL 用名词表示资源,HTTP 方法表示操作。

操作方法URL说明
查所有用户GET/api/users获取列表
查单个用户GET/api/users/1获取 ID 为 1 的用户
创建用户POST/api/usersBody 里带数据
更新用户PUT/api/users/1Body 里带数据
删除用户DELETE/api/users/1不需要 Body

看出规律了吗?URL 始终是 /api/users(名词),变的是方法(动词)。这就是 REST 的精髓。


请求头(Headers)是附加在请求上的”备注信息”。最常见的三个:

字段作用
Content-Typeapplication/json告诉后端”我发的数据是 JSON 格式”
AuthorizationBearer eyJhbGci...携带登录凭证(JWT token)
Acceptapplication/json告诉后端”我想要 JSON 格式的响应”

类比:点菜单上的备注栏。 Content-Type = “这张单子是中文写的”;Authorization = “我是 VIP 会员,卡号附上”;Accept = “请把菜装在盘子里,不要打包盒”。


前提:项目的后端已启动(task server)。

Terminal window
# 查询健康检查接口
curl http://localhost:8080/api/health

如果后端在跑,你会看到一个 JSON 响应。

Terminal window
# 开发模式登录(获取 JWT token)
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"admin@ai-tool-camp.dev"}' \
http://localhost:8080/api/auth/dev-login

拆解一下 curl 的参数:

参数含义类比
-X POST指定 HTTP 方法为 POST告诉服务员”我要下单”而不是”我看看菜单”
-H "Content-Type: application/json"设置请求头备注”这张单子是 JSON 格式的”
-d '{"email":"..."}'请求体(Body),要发送的数据点菜单上写的菜
最后的 URL请求地址把单子交给哪个窗口
Terminal window
# 假设上一步返回了 token,用它来请求需要登录的接口
curl -H "Authorization: Bearer 你的token" \
http://localhost:8080/api/users

完整流程:一次登录请求的旅程

Section titled “完整流程:一次登录请求的旅程”

把所有概念串起来,看一次登录的完整过程:

用户点击"登录"按钮
前端组装请求:
方法: POST
URL: /api/auth/login
Body: {"email": "admin@ai-tool-camp.dev", "password": "123456"}
HTTP 请求发到 localhost:8080(Vite 代理转发)
后端收到请求
查数据库,验证邮箱和密码
验证通过,生成 JWT token
返回 HTTP 响应:
状态码: 200 OK
Body: {"token": "eyJhbGci..."}
前端收到响应
保存 token 到本地存储
跳转到首页

之后每次请求,前端都会在 Headers 里带上这个 token(Authorization: Bearer xxx),后端一看 token 就知道”这个人登录过了”。


概念一句话解释
HTTP前端和后端之间的通信协议,就是”点菜-上菜”的规矩
localhost”这台电脑自己”,开发时前后端都跑在这里
端口同一台电脑上不同程序的门牌号
URL告诉浏览器”去哪里找东西”的完整地址
请求方法GET 查、POST 增、PUT 改、DELETE 删、PATCH 局部改
状态码三位数字,告诉你请求结果(2xx 成功、4xx 你的问题、5xx 服务器的问题)
Headers请求/响应的附加备注信息
Body请求/响应携带的实际数据,通常是 JSON
REST一种设计 API 的约定——URL 用名词,方法用动词
curl在终端里发 HTTP 请求的工具,测试接口用

下一步:回到主线,开始正式课程。