浏览器先到同源接口

文章详情向网站自己的 /api/session 接口发送请求。Access Token、Refresh Token 和设备标识保存在 HttpOnly Cookie 中,页面脚本拿不到令牌。Next.js 服务端从受控配置选择 App API 地址与 X-AppID,请求方不能通过一个表单字段任意切换 App。

会话代理先调用 /me 确认身份。Access Token 缺失或过期时,符合条件的请求会尝试刷新;恢复成功后再执行收藏写入。短期后端故障返回可恢复错误,已经可能执行过的写请求不会在收到失败响应后被自动重放。

这个顺序把浏览器会话恢复放在业务写入之前。排查时可以分别观察“身份没恢复”和“身份有效但操作失败”,不用把两种情况都归结为收藏按钮的问题。

收藏如何避免重复记录

App API 对发布状态和当前 App 范围做检查,用户身份来自认证上下文。浏览器无需也不能通过提交 user_id 决定收藏属于谁。持久化查询在用户与文章的唯一关系上使用冲突忽略,重复保存保留同一条记录。

取消收藏同样带租户、App、用户和文章条件。页面只显示当前用户的按钮属于交互限制,SQL 条件才会约束直接调用接口的请求。测试时应分别尝试同一用户重复保存和另一用户取消收藏。

移动端和官网经 App API 访问业务,管理端使用独立 Admin API;两条入口汇入模块化 Go 服务与 PostgreSQL。

图示说明逻辑调用关系,不表示实际部署进程数,也未提供吞吐量测试结果。

App API 与 Admin API 的权限

普通用户经 /api/v1 阅读已发布内容、管理自己的收藏。管理人员通过 /admin-api/v1 编辑、发布内容。两类 Token 的 audience 隔离,登录了官网不代表拥有后台发布权限。

一项请求还要确定租户和 App 范围。公开内容列表也有 App、发布状态及语言条件;匿名可读不等于全库可读。业务代码使用稳定错误码判断结果,页面按语言显示对应说明。

服务端实现采用 GoFrame、pgx 和 sqlc。Transport 层转换请求,Application 层安排用例与事务,Repository 执行查询,模块在启动时显式装配。相关业务仍在同一个服务内时,可以直接检查事务边界和调用栈;是否拆进程应根据负载和发布需求另行评估。

扩展字段要改哪些地方

若项目要给某条业务记录增加处理说明,先确定长度、是否必填、谁能修改和历史数据如何读取。持久字段需要迁移与 SQL;接口字段需要 OpenAPI 定义;管理端和 App 需要生成类型、输入校验及双语展示。

验收应覆盖合法保存、无权限写入、旧客户端未传字段以及并发修改。发生事务失败时,还要检查是否留下半条业务记录或已发送的外部通知。只验证新版表单能输入,无法覆盖这些条件。

定位错误时看什么

401 先查令牌与会话,403 查授权,404 查资源与允许访问的范围。列表为空时,核对当前 App、栏目筛选、发布状态和语言;后端超时则应显示错误,不能返回一个看似正常的空列表。

官网内容请求发送 Accept-Language,设置 10 秒超时,并检查 HTTP 与数据结构。请求链可以分别在 Web 代理、App API 和 SQL 层查证。代码入口见App API 契约内容查询后端蓝图