soarli

别再混淆了!白话解析 HTTP、REST 与 GraphQL 的爱恨情仇
在前后端开发中,我们每天都在和 API 打交道。但你是否真正弄清楚过 HTTP、REST 和 GraphQL 到底...
扫描右侧二维码阅读全文
01
2026/03

别再混淆了!白话解析 HTTP、REST 与 GraphQL 的爱恨情仇

在前后端开发中,我们每天都在和 API 打交道。但你是否真正弄清楚过 HTTPRESTGraphQL 到底是什么关系?很多初学者常常把它们混为一谈,甚至以为它们是互相替代的技术。

今天,我们就抛开枯燥的学术定义,用最通俗的比喻,一次性把这三者的底层逻辑理清楚。

1. HTTP 与 REST:底层协议与架构风格的完美契合

要理解它们的关系,我们先用一个极其简单的比喻:

  • HTTP 就像是“英语”:它是一门语言,拥有固定的词汇(GET、POST)和语法结构(Header、Body)。
  • REST 就像是“官方公文格式”:它是一种写作风格,规定了你该如何优雅、规范地使用这门语言。

你可以用英语写诗(标准的 REST),也可以用英语记流水账(乱写的 HTTP 接口)。

HTTP:没有感情的搬运工

HTTP(超文本传输协议)是互联网数据传输的底层规则。它只负责把数据从 A 点安全、完整地运送到 B 点。它自带了很多强大的“积木”,比如:

  • 动词(Methods): GET, POST, PUT, DELETE
  • 状态码(Status Codes): 200 (成功), 404 (找不到), 500 (服务器错误)
  • 地址(URL): 用来定位资源

REST:HTTP 的头号粉丝

REST(表述性状态转移)并非凭空发明的技术,而是一套设计指导原则。它的核心理念就是:既然你用了 HTTP,就请最大化地利用 HTTP 原本的设计!

一个优秀的 RESTful API 会极其克制且精准地使用 HTTP 的特性:

  • 用 URL 定义资源,不用动词: 获取用户是 GET /users,而不是 POST /getUser
  • 用 HTTP 动词表达动作: GET 是查,POST 是增,PUT 是改,DELETE 是删。
  • 用 HTTP 状态码表达结果: 成功就是 200,权限不足就是 403,资源不存在就是 404,绝不把所有错误都包在一个 200 OK 的壳子里。

总结:REST 依附并顺从 HTTP,试图将 API 的设计与协议本身的语义完美融合。


2. GraphQL:降维打击的“叛逆者”

如果说 REST 是“官方公文”,那么 GraphQL 就是一份塞在信封里的“高度定制调查问卷”

GraphQL 是一种查询语言运行时引擎。它的诞生是为了解决复杂应用中 REST 带来的“请求过多数据(Over-fetching)”和“请求过少数据(Under-fetching)”的问题。

但在对待 HTTP 的态度上,GraphQL 表现出了截然不同的“叛逆”:它几乎无视了 HTTP 的高级语义,仅仅把 HTTP 当作一辆运货卡车(Dumb Pipe)。

GraphQL 的“三不”原则:

  1. 不关心 URL: 不管你是查用户、删文章还是改密码,通常都只需要向一个单一的入口(例如 /graphql)发送请求。
  2. 几乎只用 POST: 因为 GraphQL 需要传递非常复杂的、嵌套的查询语句(Query),GET 请求的 URL 长度受限,所以它一股脑地把所有请求(哪怕是查询)都塞进 POST 的请求体(Body)里发过去。
  3. 万物皆可 200 OK: 这是最反直觉的一点。在 GraphQL 的世界里,只要请求成功到达了服务器的解析引擎,HTTP 层面通常永远返回 200 OK。哪怕你查的数据不存在,报错信息也会被包裹在返回的 JSON 的 errors 字段里,而不是通过 HTTP 状态码来体现。

总结:GraphQL 超越并架空了 HTTP。它在卡车的车厢里建立了一套属于自己的世界规则(Schema、Query、Resolver),卡车(HTTP)仅仅是它用来与外部世界沟通的桥梁。


3. 一图看懂三者关系

为了更直观地理解,我们可以看下这个对比表格:

对比维度HTTP (底层协议)REST (架构风格)GraphQL (查询语言/引擎)
生动比喻快递公司的卡车和信封规定信封上地址的规范写法塞在信封里的复杂自定义表格
关于 URL提供网络寻址能力极其重要,不同的 URL 代表不同的资源几乎不重要,只有一个统一入口 (/graphql)
关于 Method提供 GET, POST, PUT 等极其重要,用不同的动词代表不同的操作基本上只用 POST(作为搬运工)
关于状态码提供 200, 404, 500 等极其重要,状态码直接代表操作结果基本只回 200,具体的对错在 JSON 的 errors

结语

技术没有绝对的好坏,只有适不适合。

  • 如果你在构建一个标准的、面向公共的、需要良好利用 CDN 缓存的 Web 服务,REST + HTTP 的经典组合依然是王道。
  • 如果你在开发一个交互复杂、多端适配、且前端需要极大数据获取自由度的现代应用,GraphQL 将会是你的终极武器。

理解它们背后的设计哲学,才能在架构选型时游刃有余。

实战演练:当同一个需求遇到 REST 和 GraphQL

为了让你直观地感受到它们在实际开发中的差异,我们来设定一个非常常见的业务需求:
“获取 ID 为 1 的用户姓名,以及他最新发布的 3 篇文章的标题。”

下面我们来看看两种风格是如何交答卷的。

选手一:REST (传统的 API 调用)

在标准的 REST 架构中,资源是分散在不同 URL 里的。为了完成这个需求,前端通常会面临两种尴尬的处境。

处境 A:发送多次请求(N+1 问题)

  1. 先去 users 端点拿用户信息:
GET /api/users/1

服务器返回了一大堆数据(这就是 Over-fetching 获取过多数据):

{
  "id": 1,
  "name": "张三",
  "email": "zhangsan@example.com", 
  "age": 28,
  "address": "北京市朝阳区..." // 我只想要名字,服务器却把家底都给我了
}
  1. 接着,根据用户的 ID,去 posts 端点拿文章:
GET /api/users/1/posts?limit=3&sort=desc

服务器又返回了文章列表(包含了我不需要的内容和发布时间等):

[
  { "id": 101, "title": "深入理解 HTTP", "content": "本文将介绍...", "createdAt": "2023-10-01" },
  { "id": 102, "title": "REST 最佳实践", "content": "RESTful API...", "createdAt": "2023-10-05" },
  { "id": 103, "title": "初探 GraphQL", "content": "GraphQL 是...", "createdAt": "2023-10-10" }
]

处境 B:后端专门为你写一个定制接口
为了优化性能,后端大哥只能妥协,专门写一个不伦不类的非标准 REST 接口(比如 GET /api/getUserAndPosts),这就破坏了 REST 面向资源的优雅性,导致接口爆炸。


选手二:GraphQL (精准的自助餐)

在 GraphQL 的世界里,不管需求多复杂,前端只需要向唯一的入口(通常是 /graphql)发送一个 POST 请求,并在请求体(Body)里附上自己填好的“调查问卷”。

前端发送的请求:

POST /graphql

{
  "query": "{ user(id: 1) { name posts(last: 3) { title } } }"
}

这段查询语言翻译成人话就是:“去帮我找 id 为 1 的 user,我只要他的 name,顺便把他的 posts 拿出来,只要最后 3 篇,且文章我只要 title。

服务器返回的响应:

{
  "data": {
    "user": {
      "name": "张三",
      "posts": [
        { "title": "初探 GraphQL" },
        { "title": "REST 最佳实践" },
        { "title": "深入理解 HTTP" }
      ]
    }
  }
}

完美! 服务器返回的数据结构与前端请求的结构严丝合缝。没有多余的字段(不浪费带宽),也不需要发第二次请求(不浪费时间)。


最终总结

通过上面的代码对比,我们可以得出一个极其清晰的结论:

  • REST 就像你去一家传统中餐厅。你想吃“宫保鸡丁”里的花生米,对不起,你必须点一整盘“宫保鸡丁”(Over-fetching),如果你还想吃点青菜,你得再点一盘“炒青菜”(多次请求)。
  • GraphQL 就像你去吃自助餐。拿个盘子,你想夹两粒花生米,就夹两粒;想拿一片菜叶,就拿一片。一切由客户端(食客)精准控制。
最后修改:2026 年 03 月 01 日 07 : 02 PM

发表评论