Feed 流 API
获取首页 Feed
GET /api/v1/feed/home?cursor={cursor}&count=20
Headers:
Authorization: Bearer {token}
Response:
{
"code": 0,
"data": {
"posts": [
{
"post_id": "9876543210",
"user": {...},
"content": "微博内容",
"media": [...],
"likes_count": 100,
"comments_count": 50,
"is_liked": false,
"created_at": "2024-01-01T12:00:00Z"
}
],
"next_cursor": "cursor_string",
"has_more": true
}
}
给用户返回一个按时间或推荐排序的内容流,并支持高效分页。
接口整体设计意图
GET /api/v1/feed/home
这是一个典型的 Feed 流接口(信息流)。
GET:说明是读取资源,没有副作用 ✅/feed/home:语义清晰,表示“首页时间线”- 带
Authorization:说明是个性化 Feed(和用户强相关)
👉 本质:基于用户关注关系 + 推荐系统生成的内容流
分页设计:cursor 模式(重点)
?cursor={cursor}&count=20
cursor 分页的优势
相比传统:
?page=1&page_size=20
cursor 具备:
- ✅ 避免深分页问题(性能好)
- ✅ 适合时间流(Feed)这种不断新增的数据
- ✅ 不会出现数据错乱(翻页时数据插入导致重复/丢失)
👉 特别适用于 Feed 场景(微博、朋友圈)
cursor 通常是:
- 上一页最后一条数据的某种标记(如时间戳 / ID)
- 或者服务端生成的 opaque token(加密字符串)
例如:
next_cursor = "1698765432100_9876543210"
可能包含:
- 时间戳
- post_id
- 第一次请求:
GET /feed/home?count=20
返回:
next_cursor = A
- 下一页:
GET /feed/home?cursor=A&count=20
👉 实现的是“从 A 之后继续取”
返回结构设计
- posts 内容结构
{
"post_id": "9876543210",
"user": {...},
"content": "...",
"media": [...],
"likes_count": 100,
"comments_count": 50,
"is_liked": false,
"created_at": "..."
}
✅ 优点
- 去范式化(Denormalization)设计
user信息直接嵌入- 避免前端再请求用户接口
👉 典型 Feed 优化策略:减少请求次数
| 字段 | 作用 |
|---|---|
post_id |
唯一标识 |
user |
作者信息(冗余) |
content |
文本内容 |
media |
图片/视频 |
likes_count |
点赞数(缓存值) |
comments_count |
评论数(缓存值) |
is_liked |
当前用户是否点赞(个性化字段) |
created_at |
排序依据 |
- 个性化字段
"is_liked": false
这个很关键:
- 必须基于当前用户计算
- 通常来自:
👉 Redis / 缓存 / Like Service
- 分页控制字段
"next_cursor": "cursor_string",
"has_more": true
next_cursor:用于下一页has_more:避免客户端多发请求
👉 比 page 模式更优雅
后端实现思路(核心)
这个接口背后通常是:
1. Feed 生成模式
两种主流:
✅ 1. Push 模式(Fanout on write)
- 用户发微博时:
- 推送到粉丝的 Feed 表
- 查询时:
- 直接读 Feed 表
👉 优点:读取快
👉 缺点:写放大
✅ 2. Pull 模式(Fanout on read)
- 查询时:
- 拉取关注人的内容
- 再排序
👉 优点:写简单
👉 缺点:读复杂
✅ 3. 混合模式(实际生产)
- 大 V:pull
- 普通用户:push
2. 数据来源
Feed 数据可能来自:
- Follow Service(关注关系)
- Post Service(内容)
- Like Service(点赞状态)
- Cache(Redis)
3. 排序逻辑
可能是:
- 时间排序(倒序)
- 推荐算法排序(权重)
性能设计亮点
count=20
- 控制返回数量
- 防止接口过载
去范式化
减少请求:
Feed接口 = Post + User + Like状态 一次返回
👉 极大提升前端体验
缓存使用
常见:
- Feed 缓存(用户时间线)
- 点赞状态缓存
- 计数缓存(likes_count)
可能的优化点
字段裁剪(Feed 场景常见)
可以增加:
fields=...
减少流量
增加刷新机制
例如:
since_id / refresh_cursor
用于“下拉刷新”
Feed 类型扩展
比如:
- 推荐 Feed
- 关注 Feed
- 热门 Feed
获取用户微博列表
GET /api/v1/users/{user_id}/posts?cursor={cursor}&count=20
Response:
{
"code": 0,
"data": {
"posts": [...],
"next_cursor": "cursor_string",
"has_more": true
}
}
接口语义
GET /api/v1/users/{user_id}/posts
这是一个非常标准的 RESTful 设计:
GET:只读操作 ✅/users/{user_id}:资源归属清晰(某个用户)/posts:这个用户发布的内容集合
👉 本质:查询某个用户的历史发帖记录
和“首页 Feed”的核心区别
| 维度 | 用户微博列表 | 首页 Feed |
|---|---|---|
| 数据来源 | 单一用户 | 多用户 + 推荐 |
| 是否个性化 | ❌(基本不需要) | ✅ |
| 排序 | 时间倒序 | 时间 / 推荐 |
| 实现复杂度 | ✅ 简单 | ❌ 很复杂 |
这个接口 = 单表顺序扫描(带分页)
分页设计(依然是 cursor)
?cursor={cursor}&count=20
依然使用 cursor,而不是 page,这点很好。
即使是单用户数据,也有这些问题:
- 用户持续发微博(数据在变)
- page 分页会:
- 出现重复
- 或漏数据
👉 cursor 能保证:
- ✅ 稳定分页
- ✅ 不受新数据插入影响
对于用户 posts,cursor 通常就是:
created_at 或 post_id
例如:
cursor = 最后一条的 post_id
SQL 类似:
SELECT *
FROM posts
WHERE user_id = ?
AND post_id < cursor
ORDER BY post_id DESC
LIMIT 20;
👉 非常高效(走索引)
返回结构设计
{
"posts": [...],
"next_cursor": "cursor_string",
"has_more": true
}
1️⃣ posts
和 Feed 一样,一般会包含:
- 内容
- 媒体
- 计数(likes/comments)
- 用户信息(有时可以省略)
👉 但这里有个细节:
user 信息其实是冗余的
因为:
已经知道 user_id 了
但仍可能保留:
- 避免前端多处理
- 保持接口结构一致(和 Feed 统一)
2️⃣ next_cursor
- 用于下一页请求
- 通常是最后一条数据的标记
3️⃣ has_more
- 避免客户端多发请求
- 提升体验
后端实现
1️⃣ 数据模型
posts 表(或分库分表)
字段:
- post_id(主键 / 排序 key)
- user_id(索引)
- created_at
2️⃣ 查询路径
👉 直接查 Post 表
不需要:
- ❌ Feed 表
- ❌ 推荐系统
- ❌ 粉丝关系
3️⃣ 索引设计(重点)
必须有联合索引:
(user_id, post_id DESC)
或:
(user_id, created_at DESC)
👉 否则会慢
4️⃣ 是否需要缓存?
视情况而定:
✅ 热点用户(大 V)
- 可以缓存前几页
❌ 普通用户
- 直接查数据库即可
权限与扩展点
这个接口虽然简单,但有一些隐含设计点:
1️⃣ 是否需要登录?
这里没写 Authorization,但现实中:
- 查看公开用户:❌ 不需要登录
- 查看私密内容:✅ 需要权限
2️⃣ 是否包含草稿 / 私密微博?
可能需要区分:
viewer_id == user_id
👉 才能看到:
- 草稿
- 仅自己可见内容
3️⃣ 是否支持置顶微博?
常见需求:
- 置顶内容要插在最前面
👉 处理方式:
- 单独查一条
- 再 merge 到结果
👉 这个接口本质是:
基于 (user_id + cursor) 的顺序分页查询,是 Feed 系统中最基础、最稳定、最容易扩展的一层
更多推荐

所有评论(0)