如何使用Express JS和MongoDB搭建类似Facebook的REST API?
信息流功能完整实现方案
后端REST API设计
1. 拉取接口定义
使用GET /api/feed作为信息流拉取接口,请求参数如下:
refresh_mode:枚举值,new代表下拉刷新拉取新内容,old代表上拉加载旧内容marker_id:分页标记,刷新时传当前已加载的最新帖子ID,加载更多时传当前已加载的最旧帖子ID,首次调用传0page_size:单次拉取帖子数量,默认值建议设为15,可根据业务调整
接口返回字段:
post_list:按权重倒序排列的帖子数组,权重优先级:好友发布内容 > 关注主页/加入群组内容 > 平台推荐内容has_more:布尔值,标识是否还有更多未加载的旧内容new_post_count:刷新模式下返回,告知前端本次拉取到的新内容数量latest_marker_id、oldest_marker_id:分别对应本次返回内容的最新、最旧帖子ID,供前端存为下一次请求的标记
2. 后端聚合&去重逻辑
- 每次拉取时先获取当前用户的好友列表、关注主页ID列表、加入群组ID列表,分别拉取对应主体发布的符合可见性规则的内容,再混合推荐池内容
- 给每个用户维护已推送帖子ID集合缓存,每次拉取时直接过滤掉已经推送给用户的帖子ID,确保不会重复返回已浏览内容
- 提前1-3分钟预计算用户的信息流缓存,减少实时请求的计算耗时
React前端实现
1. 核心状态定义
可以用useState/useReducer或者状态管理库存储以下字段:
const [feedState, setFeedState] = useState({ postList: [], // 已加载的所有帖子列表 latestMarker: 0, // 已加载的最新帖子ID oldestMarker: 0, // 已加载的最旧帖子ID hasMore: true, // 是否还有更多旧内容可加载 isLoading: false // 请求中标记,避免重复发起请求 })
可以把latestMarker存在localStorage中,页面刷新后直接带入请求,避免重复展示用户已浏览过的旧内容
2. 渐进式加载逻辑
首次加载
页面初始化时调用接口,marker_id传0,refresh_mode传old,拿到返回结果后直接覆盖postList,同时更新对应分页标记和hasMore状态。
上拉加载更多
推荐用Intersection Observer监听列表底部占位元素进入视口,触发加载逻辑:
// 监听底部加载锚点 const loadMoreRef = useRef(null) useEffect(() => { const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && feedState.hasMore && !feedState.isLoading) { loadMorePosts() // 发起加载更多请求,参数marker_id传oldestMarker,refresh_mode传old } }) if (loadMoreRef.current) observer.observe(loadMoreRef.current) return () => loadMoreRef.current && observer.unobserve(loadMoreRef.current) }, [feedState])
请求返回的新帖子直接追加到postList末尾即可。
下拉刷新
触发刷新时调用接口,marker_id传latestMarker,refresh_mode传new:
- 如果
new_post_count > 0,将返回的新帖子插入到postList头部,更新latestMarker - 如果
new_post_count = 0,给用户展示"暂无新内容"的提示即可
3. 性能优化建议
- 帖子数量超过50条时,用react-window等虚拟化列表组件只渲染可视区域内的帖子,减少DOM渲染压力
- 帖子内的图片、视频等媒体资源开启懒加载,进入可视区域后再加载
- 给请求逻辑加300ms防抖,避免短时间内滚动触发多次重复请求
内容的提问来源于stack exchange,提问作者Nafis Muhymeen Tarek
相关产品推荐
相关产品推荐

