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 不是一种技术,而是一种设计风格。说白了,就是教你如何优雅地设计接口。

核心原则就几条:

  1. 资源导向:URL 里只放名词,不放动词。比如 /api/users 而不是 /api/getUsers
  2. 使用 HTTP 方法表达动作:GET 查、POST 增、PUT 改、DELETE 删。
  3. 无状态:每个请求都包含所有必要信息,服务器不保存客户端状态。
  4. 统一接口:所有资源都遵循相同的交互模式。

举个例子,一个用户管理的 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 格式,这三样东西是前后端交互的基石。你只要把这三样吃透了,大部分接口联调的问题都能迎刃而解。