API 基础与 RESTful 接口
后端核心 REST API Axios一、什么是 API
1.1 定义
API = Application Programming Interface — 定义不同软件之间如何交互的 规则和协议。
1.2 类比
API 就像两个说不同语言的人之间的 翻译官:
你的网站 (JS) ←── API ──→ 天气服务 (Python)
Program A 桥梁 Program B1.3 三个真实场景
| 场景 | 你的软件 | API 提供方 | 数据流 |
|---|---|---|---|
| 天气日记网站 | 日记应用 | OpenWeather | GET ← 获取天气数据 |
| 邮件收集 | 注册表单 | MailChimp | POST → 发送邮箱数据 |
| 智能浇花 | 电脑程序 | IoT 设备 | POST → 触发浇水 |
1.4 API 架构风格
| 类型 | 特点 | 使用场景 |
|---|---|---|
| REST ⭐ | 基于 HTTP,最流行 | Web 开发首选 |
| GraphQL | 客户端定义返回数据结构 | 复杂前端查询 |
| SOAP | XML 格式,严格规范 | 企业级/金融系统 |
| gRPC | 高性能二进制协议 | 微服务通信 |
💡 Web 开发中,REST API 是必学的。它使用我们已掌握的 HTTP 方法(GET/POST/PUT/PATCH/DELETE)。
二、请求结构
2.1 三大组成部分
https://bored-api.com/filter?type=social&participants=2
└──────── 基础 URL ──────┘└ 端点 ┘└──── 查询参数 ────────┘2.2 端点(Endpoint)
API 服务器上的 固定路由,代表不同功能:
/random → 获取随机活动
/filter → 按条件筛选活动
/activity → 获取特定活动2.3 查询参数(Query Parameters)
用于 筛选、排序、搜索:
?type=social&participants=2
↑ ↑
第一个参数 后续用 & 连接
以 ? 开始格式:?key1=value1&key2=value2&key3=value32.4 路径参数(Path Parameters)
用于 识别特定资源(ID、用户名等):
/activity/5914292
└── 路径参数(唯一标识)2.5 查询参数 vs 路径参数
| 特征 | 查询参数 | 路径参数 |
|---|---|---|
| 用途 | 筛选、排序 | 标识特定资源 |
| 位置 | ?key=value | /resource/id |
| 可选性 | 通常可选 | 通常必需 |
| 示例 | ?type=social | /user/angela |
三、JSON
3.1 什么是 JSON
JSON = JavaScript Object Notation — 轻量级数据交换格式。
3.2 JSON vs JavaScript 对象
javascript
// JavaScript 对象 — key 无需引号
const wardrobe = {
doors: 2,
drawers: 4,
color: "white"
};
// JSON — key 必须是字符串(双引号)
{
"doors": 2,
"drawers": 4,
"color": "white"
}3.3 宜家类比
| 概念 | 类比 |
|---|---|
| JS 对象 | 完整的大衣柜(占空间,不便运输) |
| JSON | 宜家平板包装(最小化体积,便于运输) |
| 序列化 | 拆解衣柜 → 装成平板包 |
| 反序列化 | 打开平板包 → 组装衣柜 |
3.4 序列化与反序列化
javascript
// JS 对象 → JSON 字符串(序列化 / 打平)
const jsonString = JSON.stringify(jsObject);
// JSON 字符串 → JS 对象(反序列化 / 组装)
const jsObject = JSON.parse(jsonString);3.5 JSON 查看器
复杂 JSON 难以阅读时,使用在线工具可视化:
四、Axios — 服务端 API 请求
4.1 为什么用 Axios
| 方式 | 代码量 | 特点 |
|---|---|---|
| 原生 Node(https 模块) | ~20 行 | 需手动处理数据块、解析 JSON |
| Axios | ~5 行 | 自动解析 JSON、简洁的错误处理 |
bash
npm i axios4.2 GET 请求
javascript
import axios from "axios";
app.get("/", async (req, res) => {
try {
const response = await axios.get("https://bored-api.com/random");
// response.data 已自动解析为 JS 对象!
res.render("index.ejs", { data: response.data });
} catch (error) {
res.render("index.ejs", { error: error.message });
}
});4.3 POST 请求
javascript
const result = await axios.post("https://api.example.com/register", {
username: "jack",
password: "secret123"
});4.4 PUT / PATCH / DELETE
javascript
// PUT — 完整替换资源
await axios.put(url, { name: "Hugo", age: 25 });
// PATCH — 部分更新
await axios.patch(url, { name: "Hugo" });
// DELETE — 删除资源
await axios.delete(url);4.5 Axios 方法签名
javascript
// GET / DELETE — 两个参数
axios.get(url, [config])
axios.delete(url, [config])
// POST / PUT / PATCH — 三个参数
axios.post(url, [data], [config])
axios.put(url, [data], [config])
axios.patch(url, [data], [config])4.6 async/await vs .then()
javascript
// ✅ 推荐:async/await(现代语法,更清晰)
async function getData() {
const response = await axios.get(url);
console.log(response.data);
}
// 也可以:.then() 链(旧语法)
axios.get(url).then(response => {
console.log(response.data);
}).catch(error => {
console.log(error);
});五、API 认证(四个等级)
5.1 认证 vs 授权
| 概念 | 含义 | 类比 |
|---|---|---|
| 认证(Authentication) | 证明你是谁 | 出示身份证 |
| 授权(Authorization) | 证明你有权限 | 出示门禁卡 |
5.2 四种认证方式
安全性递增 →
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ 无认证 │ │ Basic │ │ API Key │ │ Token │
│ │ │ Auth │ │ │ │ (OAuth) │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
防护方式: 用户名+密码 可重置的密钥 临时令牌
Rate Limit Base64编码 查询参数/Header 不暴露密码5.3 Level 0:无认证
javascript
// 任何人都可以请求,通过 Rate Limit 防止滥用
const response = await axios.get("https://bored-api.com/random");5.4 Level 1:Basic Auth
javascript
// 用户名+密码 → Base64 编码 → Authorization Header
const response = await axios.get(url, {
auth: {
username: "jack",
password: "secret123"
}
});Base64 编码
jack:secret123 → Base64 → amFjazpzZWNyZXQxMjM=
发送的 Header:Authorization: Basic amFjazpzZWNyZXQxMjM=
5.5 Level 2:API Key
javascript
// 方式 1:作为查询参数
const response = await axios.get(url, {
params: {
score: 7,
apiKey: "your-api-key-here"
}
});
// 方式 2:放在 URL 中
const response = await axios.get(
`${url}?score=7&apiKey=your-api-key-here`
);API Key 的用途:
- 追踪每个用户的请求量
- 按使用量计费
- 可以随时重新生成(不暴露密码)
5.6 Level 3:Bearer Token (OAuth)
javascript
// 第一步:用用户名密码获取 Token
const tokenRes = await axios.post(authUrl, {
username: "jack",
password: "secret123"
});
const token = tokenRes.data.token;
// 第二步:用 Token 请求 API
const response = await axios.get(url, {
headers: {
Authorization: `Bearer ${token}`
}
});OAuth 流程(第三方应用):
1. 用户在 API 提供方(如 Google)登录
2. API 提供方生成 Token
3. Token 返回给第三方应用
4. 第三方用 Token 代表用户操作
→ 用户密码始终不会暴露给第三方!六、REST API 的 CRUD 操作
6.1 完整 CRUD 示例
javascript
const API_URL = "https://api.example.com";
// CREATE — 创建资源
app.post("/create", async (req, res) => {
const response = await axios.post(`${API_URL}/secrets`, {
secret: req.body.secret,
score: req.body.score
}, {
headers: { Authorization: `Bearer ${token}` }
});
res.redirect("/");
});
// READ — 读取资源
app.get("/", async (req, res) => {
const response = await axios.get(`${API_URL}/secrets/42`, {
headers: { Authorization: `Bearer ${token}` }
});
res.render("index.ejs", { data: response.data });
});
// UPDATE (PUT) — 完整替换
app.post("/update-put", async (req, res) => {
const response = await axios.put(`${API_URL}/secrets/42`, {
secret: req.body.secret,
score: req.body.score
}, {
headers: { Authorization: `Bearer ${token}` }
});
res.redirect("/");
});
// UPDATE (PATCH) — 部分更新
app.post("/update-patch", async (req, res) => {
const response = await axios.patch(`${API_URL}/secrets/42`, {
score: req.body.score // 只更新分数
}, {
headers: { Authorization: `Bearer ${token}` }
});
res.redirect("/");
});
// DELETE — 删除资源
app.post("/delete", async (req, res) => {
await axios.delete(`${API_URL}/secrets/42`, {
headers: { Authorization: `Bearer ${token}` }
});
res.redirect("/");
});6.2 PUT vs PATCH 对比
javascript
// 原始数据:{ id: 42, secret: "My secret", score: 5 }
// PUT — 必须提供完整数据(缺少的字段会被清空)
await axios.put(url, { secret: "New secret", score: 8 });
// 结果:{ id: 42, secret: "New secret", score: 8 }
// PATCH — 只提供要修改的字段
await axios.patch(url, { score: 8 });
// 结果:{ id: 42, secret: "My secret", score: 8 }七、API 使用流程总结
1. 阅读文档 📖
├── 了解可用端点
├── 了解认证方式
└── 了解数据结构
2. Postman 测试 🧪
├── 尝试各个端点
├── 配置认证
└── 确认响应格式
3. 代码实现 💻
├── 安装 Axios
├── 构建请求
├── 处理响应数据
└── 错误处理
4. 集成到网站 🌐
├── 从前端表单获取用户输入
├── 服务端发起 API 请求
├── 将数据传递给 EJS 模板
└── 渲染到页面