当前位置: 首页 > article >正文

关注模块 API

关注用户POST/api/v1/relations/followHeaders:Authorization:Bearer{token}Request:{user_id:target_user_id}Response:{code:0,data:{relation_type:following}}接口语义设计POST /api/v1/relations/follow这是一个**创建关系Follow Relation**的动作有副作用会改变系统状态符合 RESTPOST 创建资源 本质是在创建一条(follower_id, followee_id)的关系记录请求体设计{user_id:target_user_id}user_id表示“被关注的人”followee当前用户是 从Authorization的 token 中解析follower 设计合理点不需要传follower_id避免伪造简化接口参数返回结构设计{relation_type:following}它不是随便返回的而是为了前端 UI 状态统一常见关注状态状态含义none未关注following已关注mutual互相关注 返回relation_type的好处前端无需再查一次关系状态可以直接更新按钮关注 → 已关注后端核心逻辑这个接口背后通常是一个Follow Service社交关系服务1️⃣ 数据表设计核心Follow 表单向关系follows --------- follower_id followee_id created_at 表示A 关注了 B2️⃣ 写入逻辑1. 从 token 获取 follower_id 2. 校验 - 不能关注自己 - 目标用户存在 3. 插入 follow 关系 4. 更新计数粉丝数 / 关注数 5. 返回结果3️⃣ 幂等性设计非常关键用户可能重复点击“关注” 必须保证多次请求 只生效一次常见方案✅ 数据库唯一索引UNIQUE(follower_id,followee_id)已存在 → 忽略 or 返回成功防止重复关注✅ 业务层判断不够强先查再插❌ 有并发问题不推荐单独使用计数更新粉丝数 / 关注数关注成功后通常要更新A.following_count 1 B.follower_count 1更新方式1️⃣ 同步更新简单但风险高直接 update 用户表❌ 高并发下容易成为瓶颈2️⃣ 异步更新推荐发消息RocketMQ / MQ由计数服务更新 优点解耦可扩展和 Feed 系统的联动关注行为不仅是“关系”还会影响 Feed1️⃣ Push 模式普通用户A 关注 B → 把 B 的历史微博 推送到 A 的 Feed 可能触发Fanout历史内容或只影响未来内容2️⃣ Pull 模式大 VA 关注 B → 仅记录关系 → Feed 查询时再拉取 B 内容边界情况处理1️⃣ 不能关注自己if follower_id followee_id → error2️⃣ 用户不存在返回错误码3️⃣ 已关注两种设计✅ 幂等返回成功推荐code:0relation_type:following❌ 返回错误体验差4️⃣ 黑名单 / 拉黑关系如果B 拉黑了 A A 不能关注 B扩展设计1️⃣ 双向关系是否互关可以在返回中扩展{relation_type:mutual}2️⃣ 关注来源{source:search / recommendation}用于推荐系统3️⃣ 通知系统关注后通常会触发给 B 发通知A 关注了你接口设计优点总结这个接口设计是比较标准且合理的✅ REST 语义清晰POST 创建关系✅ 参数简洁只传 target_user_id✅ 使用 token 识别用户安全✅ 返回关系状态方便前端✅ 易于扩展互关 / 推荐 / 通知 这个接口的本质是创建一条单向关注关系 保证幂等 触发计数更新和 Feed 联动取消关注POST/api/v1/relations/unfollowHeaders:Authorization:Bearer{token}Request:{user_id:target_user_id}Response:{code:0,message:取消关注成功}接口语义这里有个小问题POST /api/v1/relations/unfollow从严格 REST 角度来看关注创建关系 →POST✅取消关注删除关系 →应该是DELETE更合理更标准的设计是DELETE /api/v1/relations/follow?user_idxxx或者DELETE /api/v1/users/{user_id}/follow现实中用 POST 的原因前端调用简单不用区分 HTTP 方法某些网关/客户端对 DELETE 支持不好统一风格follow / unfollow 都是 POST 结论当前设计可用但不够 RESTful工程上是常见折中方案请求设计{user_id:target_user_id}和 follow 接口保持一致这点很好✅ 对称性强✅ 易用性高当前用户仍然从 token 中解析。返回结构设计{code:0,message:取消关注成功}和 follow 接口对比接口返回followrelation_typeunfollowmessage 这里其实不够一致更推荐的设计{code:0,data:{relation_type:none}}好处前端可以直接更新状态接口风格统一减少额外请求后端核心逻辑1️⃣ 本质操作删除一条关系记录 (follower_id, followee_id)2️⃣ 执行流程1. 从 token 获取 follower_id 2. 校验 - 不能取消关注自己 3. 删除 follow 关系 4. 更新计数 5. 返回结果3️⃣ SQL 示例DELETEFROMfollowsWHEREfollower_id?ANDfollowee_id?;幂等性设计非常关键取消关注天然是一个幂等操作取消多次 结果一样推荐行为即使用户本来就没关注 也返回成功{code:0}防止前端状态错乱避免多一次“是否关注”的查询简化调用逻辑计数更新和 follow 相反A.following_count -1 B.follower_count -1❗不能减成负数需要保证count 0推荐做法异步更新MQ或使用原子操作Redis / DB和 Feed 系统的联动取消关注不仅是删除关系还会影响 Feed1️⃣ Push 模式普通用户之前B 的内容 → 已 push 到 A 的 Feed取消关注后 有两种策略❌ 方案1删除历史 Feed很重删除 A Feed 中 B 的所有内容成本高 ❌✅ 方案2不删除只影响未来主流已存在的内容保留以后不再推送 更简单、成本更低2️⃣ Pull 模式大 V查询时过滤关注关系取消关注后直接查不到 B 的内容 天然生效 ✅边界情况1️⃣ 未关注却取消关注 应该返回成功幂等2️⃣ 用户不存在返回错误3️⃣ 自己取消关注自己非法操作4️⃣ 黑名单关系如果A 被 B 拉黑 可以自动取消关注关系优化建议总结可以改进的地方1️⃣ HTTP 方法- POST /relations/unfollow DELETE /relations/follow2️⃣ 返回结构统一- message relation_type: none3️⃣ 接口合并高级设计有些系统会这样设计PUT /api/v1/relations/follow{user_id:...,action:follow | unfollow} 优点一个接口搞定更灵活 缺点不够 RESTful 这个接口的本质是删除关注关系 保证幂等 更新计数 影响 Feed 分发策略获取关注列表GET/api/v1/users/{user_id}/following?cursor{cursor}count20Response:{code:0,data:{users:[{user_id:1234567890,nickname:用户昵称,avatar:https://...,bio:个人简介,is_following:true,is_mutual:false}],next_cursor:cursor_string,has_more:true}}接口语义GET /api/v1/users/{user_id}/following非常标准的 REST 设计GET读取资源 ✅/users/{user_id}资源归属明确/following表示“这个用户关注的人” 本质查询「user_id 关注了哪些用户」和“粉丝列表”的区别接口含义/following我关注了谁/followers谁关注了我 底层其实是同一张表两种查询方向分页设计cursor?cursor{cursor}count20继续使用 cursor这是正确的设计。关注关系会动态变化用户不断关注/取关page 分页会导致数据重复数据丢失 cursor 可以保证✅ 顺序稳定✅ 高性能走索引cursor 通常基于follow_id 或 created_atSQL 示例SELECTfollowee_idFROMfollowsWHEREfollower_id?ANDfollow_idcursorORDERBYfollow_idDESCLIMIT20; 关键点必须有顺序字段自增 ID / 时间cursor 就是“上次最后一条的位置”返回结构设计{users:[...],next_cursor:...,has_more:true}1️⃣ users 字段{user_id:...,nickname:...,avatar:...,bio:...,is_following:true,is_mutual:false}✅ 优点去范式化直接返回用户信息避免前端再查/users/{id} 和 Feed 一样减少请求次数个性化字段重点这里有两个关键字段1️⃣is_followingis_following:true这个字段其实是“当前登录用户”是否关注列表中的这个人⚠️ 注意不是{user_id}的关注关系而是viewer当前用户 → 列表中的用户2️⃣is_mutualis_mutual:false表示A 关注 B 且 B 关注 A 即“互关”❗关键点这个接口其实是“带 viewer 视角的”即使你在看B 的 following 列表返回的数据仍然包含你viewer 和这些人的关系 这就是典型的个性化查询后端实现核心1️⃣ 数据表设计Follow 表follows --------- follow_id follower_id // 谁发起关注 followee_id // 关注谁 created_at2️⃣ 查询流程1. 查 follows 表 follower_id user_id 2. 拿到 followee_id 列表 3. 批量查 users 表用户信息 4. 计算 is_following / is_mutual 5. 返回结果如何计算 is_following / is_mutual这是这个接口最“贵”的部分。1️⃣ is_followingviewer → targetviewer 是否关注了这些用户实现方式✅ 批量查询SELECTfollowee_idFROMfollowsWHEREfollower_idviewer_idANDfollowee_idIN(...)2️⃣ is_mutual双向viewer → target target → viewer实现查两次关系或缓存 性能优化关键❌ 错误做法for each user: 查一次数据库 N1 查询直接炸✅ 正确做法批量查询IN或 Redis set例如following_set(viewer_id) followers_set(viewer_id)索引设计非常关键必须有INDEX(follower_id,follow_idDESC)以及INDEX(followee_id) 否则查询关注列表慢查粉丝列表也慢缓存设计这个接口很适合缓存1️⃣ 关注列表缓存following_list:user_id2️⃣ 关系缓存following_set:user_id followers_set:user_id 用于快速判断is_followingis_mutual边界与扩展1️⃣ 是否需要登录查看列表❌ 可以不登录但is_followingis_mutual 需要 viewer2️⃣ 空列表users:[]has_more:false3️⃣ 黑名单过滤如果viewer 被某人拉黑 可以不返回该用户4️⃣ 排序方式默认按关注时间倒序也可以扩展按活跃度按推荐 这个接口的本质是基于 follower_id 的关系分页查询 用户信息聚合 viewer 视角的关系计算获取粉丝列表GET/api/v1/users/{user_id}/followers?cursor{cursor}count20Response:{code:0,data:{users:[...],next_cursor:cursor_string,has_more:true}}接口语义GET /api/v1/users/{user_id}/followers含义非常明确查询“有哪些用户关注了 user_id”和 following 的本质区别虽然结构几乎一样但查询方向完全相反接口查询条件followingfollower_id user_idfollowersfollowee_id user_idfollowing我关注谁主动关系 followers谁关注我被动关系分页设计cursor?cursor{cursor}count20依然是 cursor 分页这是必须的。因为粉丝数量可能极大百万 / 千万级且增长非常频繁大 V如果用 page❌ 深分页性能灾难❌ 数据错乱严重cursor 设计方式通常基于follow_id自增 或 created_atSQL 示例SELECTfollower_idFROMfollowsWHEREfollowee_id?ANDfollow_idcursorORDERBYfollow_idDESCLIMIT20; 本质按“谁关注你的时间”倒序返回结构{users:[...],next_cursor:...,has_more:true}和 following 保持一致这点很好✅ 接口统一✅ 前端复用逻辑users 字段设计通常包含{user_id:...,nickname:...,avatar:...,bio:...,is_following:true,is_mutual:false}个性化字段重点即使是粉丝列表也通常包含1️⃣is_followingviewer 是否关注这个粉丝 用于 UI“回关”按钮“已关注”状态2️⃣is_mutual是否互关双向关注 关系判断A → B B → A后端实现流程1️⃣ 查询 follows 表条件followee_id user_id得到follower_id 列表2️⃣ 查询用户信息users 表批量3️⃣ 计算关系状态is_followingis_mutual基于 viewer4️⃣ 返回结果这个接口的核心难点非常重要粉丝列表比关注列表更难做原因❗1️⃣ 数据量极大大 V 场景例如某大 V1000 万粉丝问题查询压力大分页很深数据冷热不均❗2️⃣ 写入非常频繁每秒成千上万用户关注 follow 表写入压力大❗3️⃣ 读取模式复杂需要排序需要分页需要 join 用户信息索引设计关键必须有这个索引INDEX(followee_id,follow_idDESC) 用于查粉丝列表核心路径同时还需要INDEX(follower_id) 用于判断 is_following查询 following性能优化重点1️⃣ 批量查询避免 N1❌ 错误for each follower: 查用户信息✅ 正确WHERE user_id IN (...)2️⃣ 缓存关系用 Redisfollowers_set:user_id following_set:user_id 用于快速判断is_followingis_mutual3️⃣ 热点用户缓存大 Vfollowers_list:user_id缓存前几页4️⃣ 分库分表核心当数据量巨大常见方案按 user_id hash 分表或按 followee_id 分片 保证单表数据量可控查询可扩展和 Feed 系统的关系粉丝列表其实决定谁会收到你的内容Push 模式Push 模式发微博 → 推送给 followers 所以followers 查询性能直接影响 FanoutPull 模式不依赖 followers 表做推送边界情况1️⃣ 无粉丝users:[]has_more:false2️⃣ 私密账号如果 user_id 是私密账号可能只返回已批准粉丝3️⃣ 黑名单如果某粉丝被拉黑 可以过滤掉和 following 的总结对比维度followingfollowers查询条件follower_idfollowee_id数据规模较小可能极大性能压力中等很高使用场景自己看被别人看 这个接口的本质是基于 followee_id 的高并发关系分页查询是社交系统中读压力最大、最需要优化的接口之一

相关文章:

关注模块 API

关注用户 POST /api/v1/relations/followHeaders:Authorization: Bearer {token}Request: {"user_id": "target_user_id" }Response: {"code": 0,"data": {"relation_type": "following"} }接口语义设计 POST /…...

仪式感,从来与你无关

2.2万人点赞的扎心评论:仪式感,从来都与你无关 有2.2万个男生偷偷点了赞。 没有歇斯底里的控诉,没有长篇大论的抱怨,只有一句轻飘飘的陈述,和一句"兄弟,没绷住"。 但就是这两句话,像一根针,精准地扎破了无数男生藏在心里最深处的、不敢说出口的委屈。 01…...

LangChain 是什么?从零开始学会 LangChain 的工程实践指南

LangChain 是什么?从零开始学会 LangChain 的工程实践指南 1. 文章背景:为什么这个主题重要 在大模型应用开发中,很多人第一次接触 LangChain,是因为想快速做一个“基于大模型的应用”:例如知识库问答、RAG 检索增强生…...

Python EXE逆向工程完全指南:使用python-exe-unpacker快速反编译打包程序

Python EXE逆向工程完全指南:使用python-exe-unpacker快速反编译打包程序 【免费下载链接】python-exe-unpacker A helper script for unpacking and decompiling EXEs compiled from python code. 项目地址: https://gitcode.com/gh_mirrors/py/python-exe-unpa…...

Pure Live:3大平台聚合,打造你的专属纯净直播空间

Pure Live:3大平台聚合,打造你的专属纯净直播空间 【免费下载链接】pure_live A Flutter project can make you watch live with ease. 项目地址: https://gitcode.com/gh_mirrors/pu/pure_live 你是否厌倦了在多个直播应用间来回切换&#xff1f…...

【RK3588-AI-004】RK3588 AI专属依赖环境预装(Python、OpenCV、基础编译工具)

📖 专栏介绍 本专栏为RK3588 端侧AI开发零基础实战教程,专为嵌入式AI入门、模型部署、视觉开发学习者打造。全程实操、无废话、避坑优化,从零搭建RK3588专属AI开发环境,手把手教学,新手也能轻松上手。 ✅ 硬件适配&am…...

深入拆解 MySQL InnoDB 隔离级别:从 MVCC 到临键锁

前言 关于 MySQL InnoDB 的事务隔离级别,90% 的开发者都存在至少一个致命误区: 误区1:RR(可重复读) 临键锁 彻底解决了幻读误区2:Serializable 只是比 RR 加的锁更多,本质还是用 MVCC误区3&a…...

2026.5.12【芯片设计面试经验分享】上海车载芯片设计公司

一、主管面试 1、介绍下负责的cpu的九级流水线都有哪级? 指令预取、PC取指、指令译码、发射(双发射)、执行1(alu、运算)、执行2(乘法、移位)、访存、写回、提交/重排 2、负责的spyglass cdc 一般…...

编译和链接+预处理

编译(compile)和链接(link)在以前我们提到过,C语言是一门编译型的计算机语言,C语言的源代码都是文本文件,文本文件本身无法运行,电脑不能执行C语言代码,计算机能够执行的…...

数分-MySQL基础01

数分-MySQL基础01基础概念MySQL数据库对象MySQL的架构MySQL客户端和服务器端连接方式命令行连接方式图形化客户端连接SQL语言分类通用语法(所有数据库)DDL语句数据库DDL数据表DDL表字段DDL数据类型字段约束基础概念 数据库(Database, DB&…...

Spring AI Alibaba 1.x 系列【55】Interrupts 中断机制:静态中断源码分析

文章目录 1. interruptBefore 模式1.1 中断判断逻辑1.2 构建中断元数据1.3 返回中断响应1.4 初始化【中断执行】上下文1.5 合并状态(BUG)1.6 执行结束 2. interruptsAfter 模式2.1 设置 INTERRUPT_AFTER 标记2.2 动态计算下一个节点 3. 中断时机对比 1. …...

【Linux驱动开发】第11天:设备树(Device Tree)超详细全解:从诞生背景到工作原理

一、设备树的诞生背景:传统驱动的致命痛点 在设备树出现之前(Linux 3.0之前),Linux内核采用硬编码的方式描述所有硬件信息。这意味着: 每一个开发板的寄存器地址、中断号、GPIO号,都直接写死在驱动代码里换…...

【Linux驱动开发】第10天:设备树零基础入门——DTS/DTB/DTC全解+编译流程

目录 为什么需要设备树?传统驱动的终极痛点DTS/DTB/DTC 大白话定义核心区别三者关系完整编译流程图最简单的DTS示例语法解析设备树编译与反编译实操命令内核如何加载和使用设备树核心总结面试必背考点 1. 为什么需要设备树?传统驱动的终极痛点 在设备树…...

TowerPersonalProperty.cs

TowerPersonalProperty 是塔的标准化攻击组件,攻击节奏(CD管理)子弹发射(从对象池获取并配置)视觉表现(旋转、动画、音效、特效)经济交互(升级/出售价格计算与金币变更)它…...

[工具] 数学题库生成器(小学,初中,高中全包括) 面向中小学数学教学的自动出题工具,覆盖从小学一年级到高中三年级共 7 个学段、33 种题型

数学题库生成器(小学,初中,高中全包括) 基本覆盖各个年级的重点题型生成,并导出为word,可以显示解题步骤。# 数学题库生成器 MathMaster 数学题库生成器(MathMaster)是一款面向中小学…...

硬件工程师,每天5分钟(5)——为什么 DDR5 最怕地不好?回流路径,才是高速设计真正的灵魂

讲透: 回流路径 为什么 Split Plane 最危险 为什么加地孔有时候能救命 为什么 GPS 会被 DDR 干扰 为什么 EMC 挂的根因常是地 🚗《硬件工程师,每天5分钟》第5篇 🔥《为什么 DDR5 最怕地不好?回流路径,才是高…...

11.三层网络VXLAN

先把之前基于flat模式创建的虚机,全部删除 控制节点配置:1.修改配置文件/etc/neutron/neutron.conf 将[DEFAULT]区域 core_plugin ml2 service_plugins 修改为 core_plugin ml2 service_plugins router allow_overlapping_ips True2.修改/etc/neutro…...

数采网关的应用与特点

摘要在工业自动化、智能制造和物联网(IoT)快速发展的背景下,数据采集网关(数采网关)作为连接现场设备与上层管理系统的关键枢纽,发挥着至关重要的作用。它能够实现工业设备数据的实时采集、协议转换、边缘计…...

第2章:文档加载与智能分块——RAG的第一步

本章你将收获:支持PDF(含表格)、Word、Markdown、网页、CSV等10+格式的完整加载代码;五种分块策略的深度对比(固定大小、递归字符、语义、文档结构、按标题);元数据保留与增强的工程方法;处理100页混合格式技术手册的完整实战;以及分块参数调优的最佳实践。 📌 本章…...

西门子PLC对接须知:从通信到编程的实战指南

在工业自动化领域,西门子S7系列PLC凭借强大的功能和广泛的兼容性,成为众多企业的首选。无论是设备集成、数据采集还是系统升级,掌握PLC对接的核心要点,是保障项目高效落地的关键。本文将从通信连接、编程架构、数据处理三个维度&a…...

ComfyUI全面掌握-知识点详解——ComfyUI 开发与扩展基础(开发指南+环境搭建)

本文为「ComfyUI 全面掌握」系列第 23 篇,是高阶进阶章节的第一篇知识点详解博客。作为开发系列的起点,本文将带你系统了解 ComfyUI 社区贡献流程,并手把手搭建完整的自定义节点开发环境,为后续的节点开发与发布奠定坚实的技术基础…...

STM32矩阵按键详解——4×4行列扫描与非阻塞消抖(硬件总结六)

前言 独立按键虽然简单,但当产品需要十几个按键时,每个按键独占一个GPIO的接法就变得很不经济。矩阵按键通过“行列”的交叉结构,仅用NM个GPIO即可驱动NM个按键。以最常见的44矩阵为例,16个按键仅需8个GPIO,引脚利用率…...

鸿蒙中的自由流转

鸿蒙自由流转是 ‌HarmonyOS(鸿蒙系统)‌ 实现多设备协同的核心能力之一,旨在打破设备边界,让应用和服务在不同终端间无缝流转,提升用户体验。‌什么是鸿蒙自由流转?‌鸿蒙自由流转是指用户在多个搭载 Harm…...

RUST编程学习.2语法

目录 前言 一、思维导图 二、Rust语法专属 1.迭代器 2.生命周期 总结 前言 在进行编译器下载后,就可以写代码进行编译调试了,在这之前就是要学习rust语法,在学习的过程中我整理了一版思维导图,最直观的感觉就是rust的语法很…...

【SSD】闪存1

闪存的特点 闪存是非易失存储器,掉电了数据也不会丢失,但是闪存不能够覆写,必须按块擦除,按页写入。 闪存的基本单元 闪存的基本单元是Cell,一种类Nmos的双层浮栅MOS管 MOS管 首先理解什么是MOS管:(金…...

性价比高的国产PLM软件公司

在制造业领域,不少企业都面临着研发效率低下、协同困难等问题。比如某电子制造企业,研发部门与生产部门之间信息沟通不畅,图纸版本管理混乱,导致产品研发周期延长,生产成本增加,新品上市时间比预期晚了近30…...

分布式团队的代码协作规范:从分支策略到提交信息格式

在分布式团队模式下,代码协作的地域分散、时区差异和沟通成本,给版本控制和质量保障带来了严峻挑战。作为软件测试从业者,我们不仅是代码质量的“守门员”,更需要深入理解并推动执行规范的代码协作流程,从分支管理到提…...

几十万买的数字孪生低代码平台集体落灰?被隐瞒的落地真相,终于说透了

在政企数字化采购圈子里,一直有个特别讽刺、且年年重复上演的现象。很多企业、政府单位,手握专项数字化预算,毫不犹豫花几十万重金购入数字孪生、3D可视化低代码平台。采购前被厂商的宣传话术打动:零代码拖拽、人人上手、无需专业…...

在家办公效率低?试试这个“空间切换”技巧

一、软件测试从业者居家办公的效率困境对于软件测试从业者而言,居家办公看似摆脱了办公室的嘈杂与束缚,实则面临着诸多独特的效率挑战。测试工作本身就需要高度的专注与严谨,从需求分析、用例设计到缺陷跟踪,每一个环节都容不得半…...

SMARTFORM不同模板一起打印

一、背景由于客户提出发货单要加上条形码打印,条形码单独一个模板,加在后面打印,输出PDF并发送邮件。二、效果展示不同模板一起打印效果如下,建立smartforms的表单时,也使用了两个不同的模板三、smartforms建立表单&am…...