API 设计
RESTful 规范
面试题:什么是 RESTful API?设计要点有哪些?
用 HTTP 方法表达对资源的操作,URL 表达资源(用名词复数,不用动词):
| 方法 | 语义 | 幂等 | 示例 |
|---|---|---|---|
| GET | 查询 | 是 | GET /users、GET /users/1 |
| POST | 新建 | 否 | POST /users |
| PUT | 全量更新 | 是 | PUT /users/1 |
| PATCH | 部分更新 | 否(视实现) | PATCH /users/1 |
| DELETE | 删除 | 是 | DELETE /users/1 |
- 常用状态码:200 成功、201 已创建、204 无内容、400 参数错误、401 未认证、403 无权限、404 不存在、409 冲突、429 限流、500 服务端错误、502/503 网关/服务不可用。
- 版本控制:
/api/v1/users或请求头Accept: application/vnd.api.v1+json。 - 分页:
?page=1&pageSize=20(普通分页)或?cursor=xxx&limit=20(游标分页,适合大数据/无限滚动)。 - 统一响应结构:
{ code, message, data },错误时返回明确的错误信息。
面试题:幂等是什么?哪些方法需要幂等?怎么保证 POST 幂等?
幂等 = 同一请求执行一次和多次效果相同。GET/PUT/DELETE 天然幂等,POST 不幂等。 保证 POST 幂等:客户端生成唯一幂等键(如 requestId),服务端用 Redis 记录已处理的 key,重复请求直接返回上次结果(防止重复下单/重复支付)。
GraphQL vs REST
| - | REST | GraphQL |
|---|---|---|
| 端点 | 多个 URL | 单一端点 |
| 取数 | 可能 over/under-fetching | 按需取数,客户端决定字段 |
| 聚合 | 多次请求 | 一次请求聚合多资源 |
| 缓存 | HTTP 缓存天然支持 | 需自行处理 |
| 成本 | 简单 | 学习成本、N+1、复杂度控制 |
GraphQL 适合字段需求多变、聚合多数据源的场景;简单 CRUD 用 REST 更轻。
实时通信
面试题:实时通信有哪些方案?怎么选?
| 方案 | 方向 | 原理 | 场景 |
|---|---|---|---|
| 短轮询 | 客户端 → 服务端 | 定时发请求 | 简单、实时性差 |
| 长轮询 | 客户端 → 服务端 | 请求挂起到有数据才返回 | 兼容性好 |
| SSE(Server-Sent Events) | 服务端 → 客户端(单向) | 基于 HTTP,text/event-stream 长连接 | 消息推送、AI 流式输出、股价 |
| WebSocket | 双向全双工 | HTTP 升级(Upgrade 头)后走 ws 协议 | 聊天、协同编辑、游戏 |
WebSocket 要点
const { WebSocketServer } = require("ws");
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws) => {
ws.on("message", (data) => {
// 广播给所有客户端
wss.clients.forEach((client) => client.send(data.toString()));
});
ws.send("connected");
});
- 握手:以 HTTP 请求带
Upgrade: websocket升级协议,之后全双工通信。 - 心跳保活:定时
ping/pong检测断线,配合断线重连。 - 集群广播:多实例下用 Redis 发布订阅(pub/sub)做跨实例消息广播(如
socket.io-redis-adapter)。
更多见 网络/websocket。
RPC 与消息队列(了解)
- RPC:像调本地函数一样调远程服务,常见 gRPC(基于 HTTP/2 + Protobuf,性能高)。微服务内部通信常用。
- 消息队列(MQ):RabbitMQ / Kafka,用于削峰填谷、异步解耦、最终一致性(如下单后异步发短信、扣库存)。
- 要会答:如何保证消息不丢失(生产确认 + 持久化 + 消费 ack)、不重复消费(消费端幂等)、顺序消费。