2.9 KiB
2.9 KiB
2026-03-13 - 文章详情预览统一与内容安全
问题 / 场景
- 文章详情目前小程序侧只展示约 20% 内容作为预览,再引导用户付费解锁。
- 历史实现中前端本地按 20% 计算预览,后端曾同时返回外层
content(预览)和data.content(全文),存在「接口约定不统一」和「误用 data.content 泄露全文」的风险。 - 需求:统一由后端按业务规则截取预览(改为 50%),小程序只按「是否已付费」选择用预览还是全文;未付费时,无论字段层级都不能拿到全文。
解决方案
- 在
internal/handler/book.go中调整章节预览逻辑:previewContent改为按字符数取正文前 50%(total/2),同时保证预览不少于 100 个字符;- 预览结尾统一追加
……(购买后阅读完整内容)作为提示文案。
- 在
findChapterAndRespond中统一内容返回策略:- 先根据 system_config.free_chapters / chapter_config.freeChapters / chapters.is_free / price 判断章节是否免费;
- 免费章节:
returnContent = ch.Content(全文); - 付费章节:
- 若
checkUserChapterAccess判断用户已购买 / VIP / 全书:returnContent = ch.Content(全文); - 否则:
returnContent = previewContent(ch.Content)(仅预览);
- 若
- 构造响应时,将
chForResponse.Content = returnContent,并通过:- 外层
content: returnContent, - 内层
data: chForResponse(其中content也为returnContent), - 确保未授权用户在任意字段上都拿不到完整正文。
- 外层
与前端的接口约定
- 小程序阅读页通过
userId查询章节详情,accessManager基于返回的章节信息与用户购买状态计算accessState:- 当
accessState为free或unlocked_purchased时,前端使用res.data.content ?? res.content渲染全文; - 当
accessState为未登录 / 未购买时,前端只使用res.content渲染预览。
- 当
- 预览比例完全由后端控制(当前为 50%),小程序不再自行用 20% 做二次截断,只是把后端提供的预览完整展示出来。
代码位置
- 后端:
soul-api/internal/handler/book.go
- 小程序(前端配合):
miniprogram/pages/read/read.jsminiprogram/pages/read/read.wxml
对后续开发的约定
- 预览长度(包括比例、最小字符数、提示文案)统一由后端控制;如需调整比例,只需修改
previewContent,保持接口字段含义不变。 - 任何需要「只返回部分内容预览」的场景,应优先复用「外层
content+ 内层data.content保持一致」的安全模式,避免在不同字段中混放全文与预览内容。 - 涉及付费内容时,优先在后端用「权限判断 + 统一内容裁剪」实现安全边界,前端只根据状态选择展示预览还是全文。