网站 API 集成基础指南:从 REST 到 GraphQL
一个内容站往往不是“一个程序”这么简单:页面要读文章列表,注册要提交表单,用户头像要上传,搜索要对接第三方……前端每做一次这类动作,背后都是一次 API 调用。API(应用程序接口)把这些数据交换约定成一套规矩,前端照着规矩请求,后端按规矩应答。这篇文章从 REST 讲到 GraphQL,帮你把网站前后端对接的基础打牢。
RESTful API 基础
REST(Representational State Transfer)是目前最流行的 API 设计风格,绝大多数公共接口——GitHub、Stripe、支付宝开放平台——都遵循它。它的核心是把一切业务对象当作“资源”,用 URL 定位、用 HTTP 方法表达动作。
核心原则
- 资源导向:每个 URL 代表一个资源(
/api/users、/api/articles) - HTTP 方法语义:GET 读取、POST 创建、PUT 更新、DELETE 删除
- 无状态:每个请求包含完成它所需的全部信息,服务端不保存会话
- 统一接口:一致的 URL 结构和响应格式,客户端无需特殊约定
设计示例
以文章模块为例,一套典型 REST 接口是这样组织的:
| 方法 | 端点 | 说明 |
|---|---|---|
| GET | /api/articles |
获取文章列表(可带分页参数) |
| GET | /api/articles/:id |
获取单篇文章 |
| POST | /api/articles |
创建文章 |
| PUT | /api/articles/:id |
更新文章 |
| DELETE | /api/articles/:id |
删除文章 |
响应通常用 JSON,并约定统一的返回结构,比如 { "code": 0, "data": [...], "message": "ok" }。状态码也要用对:200 成功、201 创建成功、400 参数错误、401 未登录、404 不存在、429 限流、500 服务端错误。前端拿到非 2xx 状态码时,应该统一进入错误分支,而不是盲目解析 body。
前端调用示例
// 使用 Fetch API 调用 REST 接口
async function getArticles() {
const response = await fetch('/api/articles');
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
}
// POST 请求
async function createArticle(data) {
const response = await fetch('/api/articles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
写前端调用时最容易漏的是两件事:一是错误处理,fetch 只有在网络异常时才 reject,HTTP 4xx/5xx 并不会抛异常,所以要手动检查 response.ok;二是取消请求,用户快速切换页面时,用 AbortController 中止掉过期请求,避免旧响应覆盖新页面状态。更系统的设计规范可以看REST API 设计指南。
GraphQL 入门
GraphQL 是 Facebook 推出的查询语言,它把“后端定接口”改成“前端按需取数”:客户端在请求里声明要哪些字段,服务端只返回这些字段。对多端复用(Web + 移动端)和字段需求差异很大的页面,能明显减少冗余传输。
REST vs GraphQL
| 特性 | REST | GraphQL |
|---|---|---|
| 数据获取 | 固定结构 | 客户端自定义 |
| 过度获取 | 常见 | 不会 |
| 多次请求 | 可能需要多次请求 | 单次请求 |
| 学习曲线 | 低 | 中 |
| 缓存 | 原生 HTTP 缓存 | 需要额外配置 |
| 工具生态 | 成熟 | 快速发展 |
GraphQL 查询示例
# 查询:只获取需要的数据
query {
articles(first: 10) {
id
title
author {
name
}
}
}
# 变更:创建数据
mutation {
createArticle(title: "Hello", content: "World") {
id
title
}
}
怎么选:一个务实的判断
对大多数中小型网站,先 REST 后 GraphQL 是更稳的路线。判断依据很简单:
- 页面多、字段需求差异大、有移动端复用 → GraphQL 的按需取数价值更高;
- 团队小、接口简单、后端已有大量 REST 代码 → 继续用 REST,避免引入 schema 与解析层的维护成本;
- 出现“一个页面要调 5 个接口才能拼齐数据”的情况,再考虑引入 GraphQL 聚合。
另外,无论选哪种方案,都要先约定好接口文档的维护方式:REST 用 OpenAPI/Swagger 描述,GraphQL 自带 introspection 能力。文档是前后端协作的地基,文档和实现不一致,联调期会浪费大量时间。
不管选哪套,接口都要做版本化(/api/v2/... 或 Accept 头),保证升级不破坏老客户端;鉴权、限流、日志这些横切能力,参考API 安全认证统一落地。后端工程实践可以看后端对接分类,例如Node.js API 示例;数据怎么存、怎么选型,见数据库选型。
常见问题
- 接口返回慢怎么办:先看是不是 N+1 查询,再看是否缺索引,最后考虑 CDN 缓存和数据库缓存。
- 要不要用 SDK:官方 SDK 封装了鉴权、重试和类型,小项目直接用
fetch也完全够。 - 跨域报错怎么排查:后端需返回正确的
Access-Control-Allow-Origin,需要携带 Cookie 时还要打开credentials。 - 联调环境怎么区分:准备
dev、staging、prod三套环境,前端用环境变量切换 baseURL,避免测试数据污染生产接口。
参考:REST 的更多最佳实践可阅读微软 Azure 架构中心的 Web API 设计文档 https://learn.microsoft.com/azure/architecture/best-practices/api-design;GraphQL 官方规范见 https://graphql.org/learn/。
前端调用
// 使用 Apollo Client 调用 GraphQL
import { ApolloClient, gql } from '@apollo/client';
const client = new ApolloClient({
uri: '/graphql',
});
const GET_ARTICLES = gql`
query GetArticles {
articles {
id
title
}
}
`;
const { data } = await client.query({ query: GET_ARTICLES });
API 安全最佳实践
身份认证
// JWT Token 认证
const response = await fetch('/api/protected', {
headers: {
'Authorization': `Bearer ${token}`
}
});
速率限制
API 端点应配置速率限制(Rate Limiting),防止滥用。
输入验证
所有 API 输入必须在服务端进行验证。
| 字段 | 验证规则 |
|---|---|
| 有效邮箱格式 | |
| title | 1-200 字符 |
| content | 1-50000 字符 |
| file | 限制大小和类型 |
16IDC 观察
对于大多数中小型网站,RESTful API 是最实用、最容易上手的选择。GraphQL 适合数据结构复杂、需要灵活数据获取的场景。建议新项目从 REST 开始,当出现「过度获取」或「多次请求」问题时再考虑引入 GraphQL。