- 新增 /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 补充新接口文档
18 KiB
番茄小说 API
Go 语言实现的番茄小说非官方 API 服务,完整实现了签名算法、设备注册、密钥管理等核心功能。
功能特性
核心功能
- 书籍搜索 - 关键词搜索,支持分页
- 书籍详情 - 获取书籍基本信息、封面、作者等
- 章节目录 - 获取完整章节列表
- 章节内容 - 获取正文内容,支持纯文本/HTML模式
- 批量接口 - 支持批量获取书籍详情和章节内容
内容类型
- 📖 小说/电子书
- 🎨 漫画
- 🎵 音频/有声书
- 🎬 视频
评论功能
- 章节段评(段落评论)
- 书籍书评
- 评论 HTML 渲染
分类体系
- 分类首页数据
- 分类详情页(支持筛选、排序、分页)
榜单与个人数据
- 🏆 榜单(推荐 / 完结 / 热搜 / 黑马 / 爆更)
- 📚 我的书架(按分组浏览,需 sessionid)
- 🕐 阅读历史(含阅读进度,需 sessionid)
技术特性
- 签名算法 - Gorgon、8404、Argus、Ladon、Khronos
- 设备密钥池 - 多设备轮换、自动补充
- 多级缓存 - 正文/详情/目录等 24 小时缓存,搜索/分类短缓存;存储后端可选 SQLite / PostgreSQL / Redis
- 配置热更新 - 修改配置无需重启
- 访问控制 - AccessKey 验证(常量时间比较防时序攻击),可扩展保护全部业务接口
- 优雅退出 - 超时保护、信号驱动的平滑关闭
- 错误规范 - 统一 JSON 错误响应,缺参 400 / 服务端错误 500
项目结构
fanqie-go/
├── cmd/fanqie/ # 程序入口
│ └── main.go # 主函数,初始化服务
├── config/ # 配置文件
│ └── config.yaml # 配置文件
├── emoji/ # 表情图片静态资源
├── internal/
│ ├── algos/ # 签名算法实现
│ │ ├── gorgon.go # Gorgon 签名算法
│ │ ├── algo8404.go # 8404 签名算法
│ │ ├── argus.go # Argus 签名算法
│ │ ├── ladon.go # Ladon 签名算法
│ │ ├── signer.go # 签名管理器
│ │ ├── switcher.go # 算法切换器
│ │ ├── sm3.go # SM3 哈希算法
│ │ ├── simon.go # Simon 对称加密
│ │ ├── pkcs7.go # PKCS7 填充
│ │ ├── protobuf.go # Protobuf 协议
│ │ └── bytebuf.go # 字节缓冲区
│ ├── common/ # 公共工具
│ │ ├── logger.go # 日志工具
│ │ ├── http.go # HTTP 工具
│ │ └── utils.go # 通用工具
│ ├── config/ # 配置管理
│ │ ├── config.go # 配置加载
│ │ └── watcher.go # 配置热更新
│ ├── fqapi/ # API 封装层
│ │ ├── cache_manager.go # SQLite 缓存管理
│ │ ├── device_key_pool.go # 设备密钥池
│ │ ├── device_register.go # 设备注册
│ │ ├── register_key.go # 密钥注册
│ │ ├── dhcry.go # DH 加密交换
│ │ ├── ttencrypt.go # TTEncrypt 加密
│ │ ├── search.go # 搜索接口
│ │ ├── detail.go # 书籍详情
│ │ ├── catalog.go # 章节目录
│ │ ├── content.go # 章节内容
│ │ ├── multi_content.go # 批量内容
│ │ ├── multi_detail.go # 批量详情
│ │ ├── item_summary.go # 章节摘要
│ │ ├── category_front.go # 分类首页
│ │ ├── category_landing.go # 分类详情
│ │ ├── audio.go # 音频
│ │ ├── video.go # 视频
│ │ ├── manga.go # 漫画
│ │ ├── manga_proxy.go # 漫画代理
│ │ ├── review.go # 评论
│ │ ├── content_parser.go # 内容解析
│ │ ├── content_utils.go # 内容工具
│ │ ├── emoji.go # 表情管理
│ │ ├── device_config.go # 设备配置
│ │ └── gorgon_utils.go # Gorgon 请求封装
│ └── handlers/ # HTTP 处理器
│ ├── common.go # 通用处理
│ ├── book.go # 书籍接口
│ ├── content.go # 内容接口
│ ├── media.go # 媒体接口
│ ├── review.go # 评论接口
│ ├── category.go # 分类接口
│ ├── manga_proxy.go # 漫画代理
│ └── status.go # 状态页面
└── go.mod # Go 模块定义
快速开始
环境要求
- Go 1.25+
- SQLite3
安装运行
# 克隆项目
git clone https://github.com/cyqddx/fanqie-go.git
cd fanqie-go
# 运行服务
go run ./cmd/fanqie
服务默认启动在 http://0.0.0.0:40180
API 接口文档
机器可读的完整接口定义见 openapi.yaml(OpenAPI 3.1,可直接导入 Swagger UI / Apifox / Postman)。
基础接口
| 接口 | 方法 | 说明 |
|---|---|---|
GET / |
GET | 服务首页 |
GET /healthz |
GET | 存活探针(不校验密钥,供容器/反代使用) |
GET /status |
GET | 服务状态(需 AccessKey) |
书籍相关
| 接口 | 方法 | 说明 | 参数 |
|---|---|---|---|
/search |
GET | 搜索书籍 | query(或 key), tab_type, offset(结果在顶层 data,已按 tab_type 过滤展平) |
/detail |
GET | 书籍详情 | book_id |
/info |
GET | 书籍详情(同 detail) | book_id |
/catalog |
GET | 章节目录 | book_id |
/directory/all_items |
GET | 章节目录(同 catalog) | book_id |
/multi-detail |
GET | 批量书籍详情 | book_id(逗号分隔) |
内容相关
| 接口 | 方法 | 说明 | 参数 |
|---|---|---|---|
/content |
GET | 章节内容 | item_id |
/multi-content |
GET | 批量章节内容 | book_id, item_ids(逗号分隔) |
/item-summary |
GET | 章节摘要 | book_id, item_ids(逗号分隔) |
评论相关
| 接口 | 方法 | 说明 | 参数 |
|---|---|---|---|
/chapter_review |
GET | 章节评论 | book_id, item_id |
/review |
GET | 书评列表 | book_id, item_id, para, comment_id, sort, offset, count |
/review_html |
GET | 评论 HTML | book_id, item_id, para, sort, page, page_size |
分类相关
| 接口 | 方法 | 说明 | 参数 |
|---|---|---|---|
/category-front |
GET | 分类首页 | - |
/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 直接登录(书源实现同样依赖浏览器人工登录)。获取方式:
- 浏览器打开 fanqienovel.com 并登录(手机验证码或密码)
- F12 → Application → Cookies → 复制
sessionid的值(有效期较长,可长期使用) - 直接传入
/bookshelf?sessionid=...或/read-history?sessionid=...使用(书架为空多半是 sessionid 无效或已过期)
媒体相关
| 接口 | 方法 | 说明 | 参数 |
|---|---|---|---|
/audio |
GET | 音频内容 | item_ids, tone_id, output |
/video |
GET | 视频内容 | item_ids |
/manga |
GET | 漫画内容 | item_ids(或 item_id), show_html, output |
/manga/image/{itemID}/{index} |
GET | 漫画图片 | 路径参数 |
内容获取示例
搜索书籍
GET http://localhost:40180/search?keyword=斗罗大陆
获取书籍详情
GET http://localhost:40180/detail?book_id=xxx
获取章节目录
GET http://localhost:40180/catalog?book_id=xxx
获取章节内容
GET http://localhost:40180/content?item_id=xxx
支持以下 URL 参数覆盖默认配置:
| 参数 | 说明 | 可选值 |
|---|---|---|
text_mode |
文本模式 | plain(纯文本), html(HTML), 或 1/0 |
img_mode(或 image_mode) |
图片模式 | remove(移除), keep(保留), 或 0/1 |
review_mode(或 review) |
评论模式 | keep(启用段评), remove(禁用), 或 1/0 |
纯文本输出(text_mode=plain 或配置 remove_html_tags: true)时不注入段评标记——<comment> 为 XML 标签,纯文本无法承载;需要段评时配置 remove_html_tags: false。
批量获取
GET http://localhost:40180/multi-detail?book_ids=id1,id2,id3
GET http://localhost:40180/multi-content?chapter_ids=id1,id2,id3
配置说明
完整配置项
配置文件位于 config/config.yaml:
# 服务器配置
server:
host: "0.0.0.0" # 监听地址
port: "40180" # 监听端口
access_key: "" # 访问密钥(可选)
protect_all: false # 业务接口也要求访问密钥(公网部署建议开启)
# 请求日志:记录 时间/IP/方法/路径/状态/耗时(query 中的 key 自动脱敏),
# 4xx/5xx 额外保留错误响应摘要(前 4KB);不记录响应体。/status 页可查看最近 20 条
request_log:
enabled: false # 是否启用
retention_days: 7 # 保留天数,自动清理
# 番茄小说配置
fanqie:
# 签名算法: "gorgon" / "8404"
algorithm: "gorgon"
# 签名方法:
# - "sign2": X-Gorgon + X-Khronos
# - "sign4": X-Gorgon + X-Ladon + X-Argus + X-Khronos
signature: "sign4"
# 内容处理
content:
remove_images: false # 移除图片
remove_image_desc: true # 移除图片描述
remove_blank_lines: true # 移除空行
remove_html_tags: true # 移除 HTML 标签
remove_chapter_title: true # 移除章节标题
add_paragraph_indent: false # 添加段落缩进
double_newline: false # 段落间双换行
enable_review: true # 启用段评
# 漫画处理
manga:
# 输出模式:
# - "proxy": 代理模式(图片已解密,推荐;"url" 返回的原始链接 404 且内容加密不可用)
# - "data_uri": Base64 编码
# - "url": 直接返回图片 URL(不可用)
output_mode: "proxy"
# 缓存配置
cache:
enabled: true # 启用缓存
backend: sqlite # 存储后端: sqlite | postgres
sqlite_path: "./cache.db" # SQLite 路径(backend 为 sqlite 时使用)
# PostgreSQL连接配置(backend 为 postgres 时使用)
postgres:
host: "127.0.0.1" # 主机
port: 5432 # 端口
user: "postgres" # 用户名
password: "" # 密码
database: "fanqie" # 数据库名
sslmode: "disable" # SSL 模式: disable | prefer | require
redis: # Redis 热缓存层(启用后与 SQL 双写:Redis 短 TTL + SQL 持久层 30 天)
enabled: false
host: "127.0.0.1" # 主机
port: 6379 # 端口
password: "" # 密码
db: 0 # 数据库编号
cleanup_enabled: true # 启用自动清理
cleanup_seconds: 86400 # 清理间隔(秒)
# 设备密钥池
device_key_pool:
enabled: true # 启用设备池
initial_size: 20 # 初始设备数
min_size: 10 # 最小设备数
max_size: 30 # 最大设备数
敏感配置(.env)
密码等敏感值不建议写进 config.yaml(会进 git 历史)。复制 .env.example 为 .env 填入真实值即可,.env 已被 gitignore:
cp .env.example .env
支持的环境变量(优先于 config.yaml 对应项):
| 环境变量 | 覆盖配置 | 说明 |
|---|---|---|
FQ_SERVER_ACCESS_KEY |
server.access_key |
服务访问密钥 |
FQ_PG_HOST |
cache.postgres.host |
PostgreSQL 主机 |
FQ_PG_USER |
cache.postgres.user |
PostgreSQL 用户名 |
FQ_PG_PASSWORD |
cache.postgres.password |
PostgreSQL 密码 |
FQ_PG_DATABASE |
cache.postgres.database |
PostgreSQL 数据库名 |
FQ_REDIS_HOST |
cache.redis.host |
Redis 主机 |
FQ_REDIS_PASSWORD |
cache.redis.password |
Redis 密码 |
已有环境变量优先于 .env 文件中的值。
配置说明表
| 配置项 | 说明 | 默认值 |
|---|---|---|
server.host |
HTTP 服务监听地址 | 0.0.0.0 |
server.port |
HTTP 服务监听端口 | 40180 |
server.access_key |
访问密钥,设为空则不验证 | - |
server.protect_all |
业务接口是否也要求访问密钥 | false |
fanqie.algorithm |
签名算法 gorgon / 8404 |
gorgon |
fanqie.signature |
签名方法 sign2 / sign4 |
sign4 |
fanqie.content.* |
正文内容处理选项 | 见上文 |
fanqie.manga.output_mode |
漫画输出模式 | proxy |
cache.enabled |
是否启用正文内容缓存 | true |
cache.backend |
SQL 存储后端 sqlite / postgres |
sqlite |
cache.sqlite_path |
SQLite 数据库路径 | ./cache.db |
cache.postgres.host |
PostgreSQL 主机 | 127.0.0.1 |
cache.postgres.port |
PostgreSQL 端口 | 5432 |
cache.postgres.user |
PostgreSQL 用户名 | postgres |
cache.postgres.password |
PostgreSQL 密码 | 空 |
cache.postgres.database |
PostgreSQL 数据库名 | fanqie |
cache.postgres.sslmode |
SSL 模式 | disable |
cache.redis.enabled |
启用 Redis 缓存(正文与音频代理缓存走 Redis) | false |
cache.redis.host |
Redis 主机 | 127.0.0.1 |
cache.redis.port |
Redis 端口 | 6379 |
cache.redis.password |
Redis 密码 | 空 |
cache.redis.db |
Redis 数据库编号 | 0 |
device_key_pool.enabled |
是否启用设备密钥池 | true |
device_key_pool.initial_size |
初始设备数量 | 20 |
device_key_pool.min_size |
最小设备数量 | 10 |
device_key_pool.max_size |
最大设备数量 | 30 |
签名算法详解
算法实现
项目实现了番茄小说的核心签名算法:
| 算法 | 文件 | 说明 |
|---|---|---|
| Gorgon | algos/gorgon.go |
核心签名算法,生成 X-Gorgon、X-Khronos、X-SS-REQ-Ticket |
| 8404 | algos/algo8404.go |
另一种签名算法实现 |
| Argus | algos/argus.go |
增强签名,包含 ProtoBuf、SM3、Simon、AES 加密 |
| Ladon | algos/ladon.go |
附加签名,基于 MD5 变换 |
| Khronos | 内嵌于 Gorgon | 时间戳签名 |
签名方法
- sign2: X-Gorgon + X-Khronos(基础签名)
- sign4: X-Gorgon + X-Ladon + X-Argus + X-Khronos(完整签名)
设备密钥池
项目实现了设备密钥池管理:
- 自动注册 - 启动时自动注册多个设备
- 密钥轮换 - 请求时自动切换设备
- 自动补充 - 设备数量低于阈值时自动注册新设备
- 持久化存储 - 设备信息保存到 SQLite
缓存机制
Redis 启用时为双层架构:Redis 热层(TTL=业务缓存时长)+ SQL 持久层(不可变内容固定保留 30 天)。
- 读:Redis → 未命中查 SQL(命中自动回填 Redis)→ 回源上游
- 写:Redis + SQL 双写;搜索/分类等动态短缓存只走 Redis 不落库
- 防击穿:singleflight 合并并发未命中请求,同一 key 只有一个请求打上游
- 自动清理 - 定期按行内过期时间清理 SQL 过期缓存(Redis 由 TTL 自动过期)
- 数据库压缩 - 支持 VACUUM 操作优化数据库
| 接口 | 缓存时长 |
|---|---|
/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 有效期) |
失败响应不缓存;评论类接口为动态数据,不缓存。
部署
Linux 服务器(deploy.sh 一键部署)
# 首次:编译 + 部署 + 写入 systemd/nginx 配置
./deploy.sh v1.0.0 --init
# 日常:拉取代码 + 编译 + 部署 + 重启
./deploy.sh v1.0.0
# 版本管理
./deploy.sh --list # 列出已部署版本
./deploy.sh --rollback v1.0.0 # 回滚到指定版本
# 服务运维
sudo systemctl status fanqie
sudo journalctl -u fanqie -f
部署结构:二进制存于 /opt/fanqie/bin/,fanqie-current 软链接指向当前版本(保留最近 5 个),systemd 守护 + Nginx 反代,部署后自动做 /healthz 健康检查。
首次 --init 时若服务器装有 certbot,会自动申请 HTTPS 证书并配置 80→443 跳转(邮箱默认 admin@域名,可用 .deploy.env 的 CERT_EMAIL 覆盖);续期由 certbot.timer 自动完成,续期后经 deploy-hook 重载 Nginx。
本地交叉编译
make build-linux VERSION=v1.0.0 # 产物 fanqie-v1.0.0-linux,scp 到服务器即可运行
技术栈
- Go 1.25 - 编程语言
- net/http - 标准库 HTTP 服务(超时保护 + 优雅退出)
- SQLite3 / PostgreSQL / Redis - 缓存与存储
- Viper - 配置管理
- goquery - HTML 解析
注意事项
- 本项目仅供学习和研究使用
- 请遵守番茄小说的服务条款
- 请合理使用,避免对官方服务造成影响
- 签名算法和设备注册可能随时失效
License
MIT License