DailyHotApi:把分散的热榜接成统一 JSON 与 RSS API
微博、知乎、哔哩哔哩和技术社区都有自己的热门列表,但返回格式、访问方式和更新频率并不一致。要做一个聚合阅读页,直接对接每个来源意味着分别处理接口、网页结构、缓存和异常。
DailyHotApi 把这些差异收在一个服务里。调用者请求 /weibo、/zhihu、/bilibili 等路径,就能拿到结构相近的 JSON;需要订阅时,同一路由还可以输出 RSS。DailyHotApi 适合个人信息面板、展示屏、机器人或低频聚合任务,不是带用户、收藏和阅读状态的完整资讯产品。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | DailyHotApi |
| 项目描述 | 聚合多个公开热榜的数据接口,支持 JSON 与 RSS 输出 |
| GitHub 仓库 | imsyy/DailyHotApi |
| 官网地址 | 今日热榜示例前端 |
| 当前发布版本 | v2.0.8(发布于 2025-08-20) |
| 主要开发语言 | TypeScript 98.38%、Dockerfile 0.63%、JavaScript 0.57% |
| 开源许可证 | MIT |
| 最近代码更新 | 2026-03-11(GitHub pushed_at;核对日期:2026-09-14) |
先用一条接口理解返回结果
部署好的实例以路由文件名作为接口路径。例如请求哔哩哔哩热榜:
curl --fail --silent --show-error \
"http://127.0.0.1:6688/bilibili?limit=3"成功时返回对象包含来源名称、榜单类型、更新时间、缓存状态、总数和 data 列表。列表项通常会整理出 id、title、url、mobileUrl、hot 等字段,但并非每个上游都能提供所有字段。调用端应把可选字段当作可选值处理,不要假设不同来源的数据天然可比较。
| 调用 | 作用 | 使用提醒 |
|---|---|---|
GET /all | 返回当前实例发现的全部路由 | 适合生成数据源选择器,不代表每个上游此刻都可用 |
GET /weibo | 获取指定来源的数据 | 路径名来自 src/routes 下的文件名 |
?limit=10 | 截取前 10 条 | 调用端仍应防御非法或超出范围的值 |
?cache=false | 注册层向适配器传递绕过缓存的意图 | 适配器实现并不完全一致,接入前要实测 |
?rss=true | 将结果输出为 RSS 2.0 | RSS_MODE=true 也可令路由默认输出 RSS |
带自身参数的路由会在返回数据的 params 中说明可选项。例如哔哩哔哩支持不同排行榜分区,GitHub Trending 支持 type=daily|weekly|monthly。新增调用前应请求目标路由或阅读对应路由文件。通用注册层虽然会解析 cache=false,固定提交的哔哩哔哩主接口却硬编码为使用缓存,说明适配器可能没有完整传递通用参数。
README 列出的公共 API 域名 api-hot.imsyy.top 在 2026-09-14 的核验环境中无法完成 DNS 解析,因此本文不把该域名作为可用性保证。只想了解展示效果可以访问作者列出的示例前端;需要稳定集成时,使用自己控制的实例更便于限制访问、观察错误和调整缓存。
三种采用方式怎么选
| 方式 | 适合场景 | 主要代价 |
|---|---|---|
| 调用公共实例 | 临时试验,不传 Cookie 或其他秘密 | 地址、限流、可用性和缓存策略不由自己控制 |
安装 dailyhot-api npm 包 | 已有 Node.js 程序,希望在进程中启动服务 | 要共同承担端口、日志、生命周期和依赖升级 |
| Docker 自托管 | 希望独立运行、限制入口并能固定版本 | 需要维护镜像构建、网络、日志和上游变化 |
npm 包要求 Node.js 20 或更高版本:
pnpm add dailyhot-apiimport serveHotApi from "dailyhot-api";
serveHotApi(3000);这会启动一个 HTTP 服务,而不是返回一组可直接调用的抓取函数。需要和现有 Web 框架共用路由、中间件或进程健康管理时,独立部署通常更清晰。
缓存解决什么,又没有解决什么
请求进入具体数据源后,通用请求工具会先查缓存。默认缓存时间为 3600 秒;没有配置 Redis 或 Redis 连接失败时,服务退回进程内的 NodeCache,最多保存 100 个 key。进程内缓存会在容器重启后消失,多副本之间也不共享。
Redis 保存的是可重新抓取的数据,不是必须备份的业务记录。多个应用副本可以共享 Redis 中的结果;缓存能否跨 Redis 重启完整保留,取决于 RDB、AOF 等持久化配置。当前实现的缓存 key 主要取上游 URL。阅读新路由代码时,应检查请求参数或 POST body 是否完整进入 URL,否则不同参数可能复用同一个 key。
缓存可以降低请求频率,无法修复源站改版、访问封禁、Cookie 失效或地区网络限制。仓库 issue 中已有知乎 401、微博 403和部分榜单 500的报告。生产调用应设置超时、重试上限与降级展示,并把单一来源失败和整个聚合服务不可用分开处理。
用固定源码提交部署
项目版本:DailyHotApi 源码提交 36c77e3,包版本 2.0.8。部署日期:2026-09-14(配置核验日期,未实际启动容器)。
当前固定提交晚于 v2.0.8 标签;README 提供的镜像命令使用可漂移的 latest,无法证明与本文分析的源码一致。因此下面从固定提交本地构建。准备安装了 Git、Docker Engine 和 Compose 插件的 Linux 主机,并确保主机能够访问 GitHub、npm 软件源以及计划使用的上游站点。
获取源码并创建配置
git clone https://github.com/imsyy/DailyHotApi.git dailyhot-api
cd dailyhot-api
git checkout 36c77e3bd891c11642d314cfb229bf31646704de
git status --short最后一条命令应无输出。复制项目的环境变量示例:
cp .env.example .env
chmod 600 .env第一次部署至少检查这些值:
PORT=6688
ALLOWED_DOMAIN="https://your-frontend.example"
ALLOWED_HOST=".your-frontend.example"
DISALLOW_ROBOT=true
CACHE_TTL=3600
REQUEST_TIMEOUT=6000
USE_LOG_FILE=true
RSS_MODE=falseALLOWED_DOMAIN 应填写主站的精确 Origin;命令行和服务端调用仍可直接请求接口。需要放行子域时,ALLOWED_HOST 可填写带前导点的 .your-frontend.example。源码直接执行字符串 origin.endsWith(ALLOWED_HOST),不解析 URL hostname;省略前导点会连 evilyour-frontend.example 这类相似主机一起匹配。空字符串也无法关闭规则,因为源码会回退到 imsyy.top。不需要子域或要求严格白名单时,应在反向代理层校验并覆盖 CORS 响应。中间件还设置了 credentials: true,浏览器不接受凭据请求与通配 Origin 的组合,带 Cookie 的前端必须配置明确来源。
创建 compose.yaml:
services:
dailyhot-api:
build:
context: .
target: runner
image: local/dailyhot-api:36c77e3
restart: unless-stopped
ports:
- "127.0.0.1:6688:6688"
env_file:
- .env
volumes:
- dailyhot-logs:/app/logs
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:6688/').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
interval: 30s
timeout: 8s
retries: 3
start_period: 30s
volumes:
dailyhot-logs:端口只绑定到回环地址,适合本机使用或交给同机 HTTPS 反向代理。项目自带 Compose 使用 user: "114514",但镜像在构建阶段创建的是 UID 1001 用户;这里保留 Dockerfile 的默认用户,避免日志目录权限被不相关 UID 覆盖。健康检查只证明首页 HTTP 可访问,不能代表所有上游路由正常。
构建、启动和业务验收
docker compose config --quiet
docker compose build --pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 dailyhot-apiconfig --quiet 无输出且退出码为 0,表示配置能够解析。容器变为 healthy 后,检查路由目录,再选择两个不同类型的数据源:
curl --fail --silent --show-error http://127.0.0.1:6688/all
curl --fail --silent --show-error \
"http://127.0.0.1:6688/bilibili?limit=2"
curl --fail --silent --show-error \
"http://127.0.0.1:6688/github?type=daily&limit=2"
curl --fail --silent --show-error \
"http://127.0.0.1:6688/bilibili?limit=2&rss=true" \
| head -n 10验收时检查 JSON 中的 name、updateTime、fromCache、total 和 data,并确认 RSS 命令返回 XML。第二次请求同一路由时,fromCache 应反映缓存命中。某条上游失败时先查看容器日志,再从部署主机直接检查该源站是否可达;首页健康不能排除上游反爬或页面结构变化。
接入 Redis
单实例、可接受重启后重新抓取时,内存缓存已经能工作。需要共享缓存或为 Redis 持久化预留磁盘时,再向 Compose 添加 Redis,并在 .env 中设置 REDIS_HOST=redis、REDIS_PORT=6379:
redis:
image: redis:7.4-alpine
restart: unless-stopped
volumes:
- dailyhot-redis:/data同时在顶层 volumes 增加 dailyhot-redis:。该卷提供 Redis 数据落盘位置,但默认 RDB 策略不保证保存最后一次快照之后的缓存写入。正式环境应固定 Redis 镜像摘要,并按网络边界决定是否设置密码;Redis 无需发布宿主机端口。应用连接失败会降级为内存缓存,因此应从日志确认 Redis 已连接,接口仍返回数据不足以证明 Redis 正常。
公网暴露前要补的控制
DailyHotApi 本身没有 API Key、用户或速率限制。反向代理到公网前,至少增加 HTTPS、认证或受控来源、请求频率限制、响应超时和日志脱敏。其中 cache=false 需要按路由实测并在代理层限制;确实支持该参数的适配器会把匿名高频请求压力传给上游。
某些来源需要 ZHIHU_COOKIE 等登录信息。秘密只应保存在权限受控的 .env 或专用 secrets 系统中,不要提交到 Git,也不要出现在截图、支持工单或代理访问日志里。把个人 Cookie 放到公共实例,会同时扩大账号和内容访问风险。
这个项目聚合的是第三方公开页面或接口。MIT 许可证适用于 DailyHotApi 的代码,不自动授予上游内容的复制与再分发权。对外提供服务前,需要核对各来源的服务条款、robots 规则、访问频率、版权和当地法律要求。
更新、回滚与卸载
更新时先在仓库发行页和提交历史中选定目标提交,不要直接把 master 或 latest 当成版本:
git fetch origin
git checkout <verified-commit>
docker compose build --pull
docker compose up -d
docker compose ps随后重复 /all、两条代表性 JSON 路由、RSS 和缓存验收。若新版本失败,重新检出本文“验证边界”中的固定提交,构建并启动即可回滚。日志与 Redis 都不是不可替代业务数据,但旧 .env 和旧提交号应保留到验收完成。
停止服务使用 docker compose down,该命令会保留命名卷。确认不再需要日志与 Redis 缓存后,docker compose down -v 会一并删除这些卷;该操作不可用于仍需保留排障日志的实例。
新增一个数据源时发生什么
src/registry.ts 会递归扫描 src/routes 下的 .ts 或 .js 文件,以文件名生成 URL 路径,并在请求时动态导入模块的 handleRoute。因此新增来源的主要入口是一份路由文件,而不是手工维护中央路由表。
典型路由负责读取自身参数、调用上游并转换列表、返回统一的 RouterData。通用注册层再处理 limit、cache=false 和 RSS 输出。src/utils/getData.ts 提供 HTTP 请求与缓存,src/utils/getRSS.ts 把统一结构转换成 RSS 2.0。
动态注册结构降低了增加来源的门槛,也让故障集中在单个适配器。新增路由时至少测试正常数据、空列表、上游超时、字段缺失、缓存命中和 RSS 转换。抓网页的路由还应把选择器失效视为预期故障,不应使用非空断言掩盖选择器失效。
正在准备渲染...
查看源码
flowchart LR
Client[客户端] --> Registry[动态路由注册层]
Registry --> Adapter[数据源 handleRoute]
Adapter --> Cache{Redis 或内存缓存}
Cache --> Upstream[上游 API 或网页]
Adapter --> Normalize[统一 RouterData]
Normalize --> JSON[JSON 响应]
Normalize --> RSS[RSS 2.0]和其他做法相比
DailyHotApi 的重点是“榜单 JSON 优先,并可转 RSS”。RSSHub 的核心是覆盖更广的订阅路由与 RSS 生态,适合交给阅读器长期订阅;直接调用上游 API 则最少一层依赖,但每个来源的认证、格式、缓存和变更都要自己承担。
如果目标是快速做一个多来源热榜页面,DailyHotApi 的统一结构更直接。如果目标是构建可长期迁移的阅读订阅,先评估网站原生 RSS 和 RSSHub。如果只有一个稳定且有正式开放 API 的来源,直接对接往往更简单,也更容易遵守调用规则。
总结
DailyHotApi 的价值在于把数据源适配、缓存和 JSON/RSS 输出整理成一套容易接入与扩展的约定。上游变化仍会直接影响具体榜单,因此长期使用需要区分单路由故障、限制高频刷新,并为重要来源准备降级方案。
第一次试用建议从本机固定提交部署开始,验收 /all、一条 API 型来源、一条网页抓取型来源和 RSS 输出。只有这些路径在自己的网络环境中稳定,再接入前端或自动化任务。
验证边界
本文基于固定提交 36c77e3,核对日期为 2026-09-14。已静态阅读 README、包清单、应用入口、动态路由注册、缓存、RSS、代表性数据源、Dockerfile、Compose 和环境变量示例;已确认示例前端与作者部署文章可访问。未安装依赖,未执行目标代码,未构建或启动容器,未验证命令输出、Redis 降级、持久化、更新回滚或真实上游接口。README 中的公共 API 域名在核验环境中 DNS 解析失败。