2、前端与后端数据交互:HTTP协议基础、RESTful API设计原则、JSON数据格式详解
好,咱们直接进入正题。前端和后端怎么「说话」?说白了,就是通过 HTTP 协议。你想想看,浏览器里的页面要展示数据,总得有个渠道去服务器拿吧?这个渠道就是 HTTP。
2.1 HTTP 协议基础:你每天都在用,但可能没细想过
HTTP 的全称是超文本传输协议。嗯,名字挺长,但核心就两件事:请求和响应。
前端发一个请求,后端给一个响应。就这么简单。
我个人习惯把 HTTP 请求拆成三部分来看:
- 请求行:包含方法(GET、POST 等)、URL、协议版本。
- 请求头:携带一些元信息,比如 Content-Type、Authorization。
- 请求体:真正要传给后端的数据,通常是 JSON 格式。
响应也是类似的套路:状态行(状态码)、响应头、响应体。
我在项目中遇到过一个问题:前端明明发了请求,后端却收不到数据。排查了半天,发现是 Content-Type 没设置对。后端期待的是 application/json,前端默认发的是 application/x-www-form-urlencoded。嗯,这种坑踩过一次就记住了。
核心要点:HTTP 是无状态的。每次请求都是独立的,服务器不会记住你上次干了什么。所以登录状态要靠 Token 或 Session 来维护。
2.2 常见的 HTTP 方法
你平时写接口,最常用的就是 GET 和 POST。但 RESTful 风格下,还有 PUT、DELETE、PATCH 这些。
| 方法 | 用途 | 幂等性 | 请求体 |
|---|---|---|---|
| GET | 获取资源 | 是 | 无 |
| POST | 创建资源 | 否 | 有 |
| PUT | 更新资源(全量) | 是 | 有 |
| PATCH | 更新资源(部分) | 否 | 有 |
| DELETE | 删除资源 | 是 | 通常无 |
为什么会强调幂等性?举个例子:你点了一次「提交订单」,结果网络卡了,你又点了一次。如果 POST 不是幂等的,那就会生成两个订单。我曾经在电商项目里就因为这个被用户投诉过……后来加了防重令牌才解决。
2.3 状态码:后端给前端的「暗号」
状态码是后端告诉前端「这次请求结果如何」的信号。我建议你记住这几类:
- 2xx:成功。200 是标准成功,201 是创建成功。
- 3xx:重定向。301 永久重定向,302 临时重定向。
- 4xx:客户端错误。400 参数错误,401 未认证,403 无权限,404 找不到资源。
- 5xx:服务器错误。500 内部错误,502 网关错误,503 服务不可用。
避坑指南:我曾经见过一个项目,不管什么错误都返回 200,然后在响应体里放一个 code 字段表示成功或失败。这种做法其实很不规范。前端每次都要先解析 body 才知道有没有报错,非常麻烦。我建议你严格遵循 HTTP 状态码的语义,该 400 就 400,该 500 就 500。
2.4 RESTful API 设计原则
REST 不是一种技术,而是一种设计风格。说白了,就是教你如何优雅地设计接口。
核心原则就几条:
- 资源导向:URL 里只放名词,不放动词。比如
/api/users而不是/api/getUsers。 - 使用 HTTP 方法表达动作:GET 查、POST 增、PUT 改、DELETE 删。
- 无状态:每个请求都包含所有必要信息,服务器不保存客户端状态。
- 统一接口:所有资源都遵循相同的交互模式。
举个例子,一个用户管理的 API 应该是这样的:
GET /api/users # 获取用户列表
GET /api/users/123 # 获取单个用户
POST /api/users # 创建用户
PUT /api/users/123 # 更新用户(全量)
PATCH /api/users/123 # 更新用户(部分)
DELETE /api/users/123 # 删除用户
我在项目中遇到过有人把接口设计成 /api/deleteUser 和 /api/updateUser 这样的。嗯,不能说错,但维护起来会很痛苦。你想想看,如果资源多了,每个资源都要写一套动词,那接口数量会爆炸。
注意:RESTful 不是银弹。如果你的业务逻辑非常复杂,比如批量操作、事务性操作,REST 可能不太适合。这时候可以考虑 RPC 风格或者 GraphQL。
2.5 JSON 数据格式详解
JSON 现在是前后端数据交互的事实标准。为什么?因为它简单、易读、几乎所有语言都支持。
一个标准的 JSON 对象长这样:
{
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"age": 28,
"isActive": true,
"tags": ["前端", "后端", "全栈"],
"address": {
"city": "北京",
"district": "海淀"
}
}
几个关键点:
- 键名必须用双引号,单引号不行。
- 字符串用双引号,数字和布尔值不用。
- 支持嵌套,对象里可以套对象,数组里可以套对象。
- 不支持注释,所以别想着在 JSON 里写注释。
我个人习惯在返回列表数据时,加上分页信息:
{
"code": 200,
"message": "success",
"data": {
"list": [...],
"total": 100,
"page": 1,
"pageSize": 20
}
}
这样前端拿到数据后,可以直接渲染表格和分页组件,不用再额外请求一次。
小技巧:前后端约定好字段命名风格。我建议统一用 camelCase(驼峰命名),比如 createdAt 而不是 created_at。虽然后端数据库可能用下划线,但 JSON 传输时转成驼峰,前端用起来更顺手。
2.6 实战中的常见问题
最后聊几个我踩过的坑:
- 跨域问题:前端请求后端时,如果域名不同,浏览器会拦截。解决方案是后端加 CORS 头,或者用代理。
- JSON 序列化循环引用:对象里有相互引用时,JSON.stringify 会报错。我一般用第三方库或者手动处理。
- 大 JSON 性能问题:如果返回的数据量很大,比如几万条,前端解析会卡顿。建议后端做分页,或者前端用虚拟列表。
嗯,这一章的内容就到这里。HTTP 协议、RESTful 设计、JSON 格式,这三样东西是前后端交互的基石。你只要把这三样吃透了,大部分接口联调的问题都能迎刃而解。