✨ feat(api): 新增榜单书架历史与搜索续传并重构正文缓存链路

- 新增 /rank 免签名榜单接口(多域名容错)、/bookshelf 与 /read-history(sessionid 登录态,书架支持分组过滤)
- 搜索重写:翻页透传上游 passback/search_id/next_offset/corrected_query 并按 book_id 去重,15~20 位纯数字关键词直查详情(ID 直搜)
- 删除 /login/check 登录校验端点(login.go、路由与文档同步移除,sessionid 说明改为直接供书架/历史使用)
- 正文链路重构:singleflight 合并同章节并发回源防击穿,缓存与解析解耦统一在出口处理,decodeContentBody 按 crypt_status 分支并兜底 500003 明文
- 缓存层:SQL 持久层 TTL 与业务 TTL 解耦(不可变内容过期后由 SQL 回填),动态短缓存只走 Redis,withCache 合并并发 miss
- 密钥池:KeyTs 随正文请求上传降低密钥不匹配重试,密钥超 24 小时异步刷新并防刷新风暴,last_used_at 批量落库
- 签名补 X-Helios(与 X-Ladon 同值,对齐书源实现);设备注册版本号统一走 ClientVersionCode/Name
- 分类 landing 透传新版标签 selected_items;multi-detail 批量详情供书架/历史复用
- README 与 openapi.yaml 补充新接口文档
This commit is contained in:
chenxin committed 2026-10-12 14:49:14 +08:00
1 parent 8ca372050b
commit 84bd3238ab
28 files changed
+1180 -270

No files matched your search

+33 -7
View File
@@ -30,6 +30,12 @@ Go 语言实现的番茄小说非官方 API 服务,完整实现了签名算法
- 分类首页数据
- 分类详情页(支持筛选、排序、分页)
### 榜单与个人数据
- 🏆 榜单(推荐 / 完结 / 热搜 / 黑马 / 爆更)
- 📚 我的书架(按分组浏览,需 sessionid)
- 🕐 阅读历史(含阅读进度,需 sessionid)
### 技术特性
- **签名算法** - Gorgon、8404、Argus、Ladon、Khronos
@@ -171,7 +177,23 @@ go run ./cmd/fanqie
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/category-front` | GET | 分类首页 | - |
| `/category-landing` | GET | 分类详情 | `category_id`, `word_number`, `book_status`, `sort_by`, `offset` |
| `/category-landing` | GET | 分类详情 | `category_id`, `word_number`, `book_status`, `sort_by`, `offset`, `selected_items`(新版分类标签自带筛选项,透传上游) |
### 榜单与个人数据
| 接口 | 方法 | 说明 | 参数 |
| ------ | ------ | ------ | ------ |
| `/rank` | GET | 榜单(免签名接口) | `side_type`(`10` 推荐 / `11` 完结 / `12` 热搜 / `13` 黑马 / `15` 爆更,默认推荐), `page`(默认 1,每页 20 本) |
| `/bookshelf` | GET | 我的书架(需登录) | `sessionid`(必填,见下方「获取 sessionid」), `group`(可选,按分组过滤;响应含每本书的 `group_name`) |
| `/read-history` | GET | 阅读历史(需登录) | `sessionid`(必填), `offset`(默认 0,每页 20 条;响应每项的 `history` 字段保留上游原始记录,含阅读进度) |
#### 获取 sessionid
番茄网页版登录由字节风控(滑块验证)保护,无法通过 API 直接登录(书源实现同样依赖浏览器人工登录)。获取方式:
1. 浏览器打开 [fanqienovel.com](https://fanqienovel.com/) 并登录(手机验证码或密码)
2. F12 → Application → Cookies → 复制 `sessionid` 的值(有效期较长,可长期使用)
3. 直接传入 `/bookshelf?sessionid=...` 或 `/read-history?sessionid=...` 使用(书架为空多半是 sessionid 无效或已过期)
### 媒体相关
@@ -288,7 +310,7 @@ cache:
password: "" # 密码
database: "fanqie" # 数据库名
sslmode: "disable" # SSL 模式: disable | prefer | require
redis: # Redis 缓存(正文缓存与音频代理缓存,统计数据/设备池仍在 SQL 库)
redis: # Redis 热缓存层(启用后与 SQL 双写:Redis 短 TTL + SQL 持久层 30 天)
enabled: false
host: "127.0.0.1" # 主机
port: 6379 # 端口
@@ -388,15 +410,19 @@ cp .env.example .env
## 缓存机制
- **接口缓存** - 命中直接返回,不打上游(Redis 启用时优先走 Redis)
- **自动清理** - 定期清理过期缓存(Redis 由 TTL 自动过期)
Redis 启用时为**双层架构**:Redis 热层(TTL=业务缓存时长)+ SQL 持久层(不可变内容固定保留 30 天)。
- **读**:Redis → 未命中查 SQL(命中自动回填 Redis)→ 回源上游
- **写**:Redis + SQL 双写;搜索/分类等动态短缓存只走 Redis 不落库
- **防击穿**:singleflight 合并并发未命中请求,同一 key 只有一个请求打上游
- **自动清理** - 定期按行内过期时间清理 SQL 过期缓存(Redis 由 TTL 自动过期)
- **数据库压缩** - 支持 VACUUM 操作优化数据库
| 接口 | 缓存时长 |
| ------ | ------ |
| `/content` | 24 小时 |
| `/detail`、`/info`、`/catalog`、`/multi-detail`、`/item-summary` | 24 小时 |
| `/search`、`/category-front`、`/category-landing` | 10 分钟 |
| `/content`、`/multi-content` | 24 小时(SQL 层 30 天) |
| `/detail`、`/info`、`/catalog`、`/multi-detail`、`/item-summary` | 24 小时(SQL 层 30 天) |
| `/search`、`/category-front`、`/category-landing` | 10 分钟(仅 Redis) |
| `/audio` 代理链接 | 2 小时(匹配 CDN 有效期) |
失败响应不缓存;评论类接口为动态数据,不缓存。