news 2026/10/1 1:54:43

NewsNow 完整部署与扩展指南:优雅实时新闻聚合平台的缓存、登录、MCP 与数据源架构解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NewsNow 完整部署与扩展指南:优雅实时新闻聚合平台的缓存、登录、MCP 与数据源架构解析
  • 前端
  • 后端
  • 网页爬虫

【免费下载链接】newsnow

Elegant reading of real-time and hottest news

项目地址:https://gitcode.com/GitHub_Trending/ne/newsnow
点击查看免费下载

NewsNow 是一个主打"优雅阅读实时热门新闻"的开源 Web 应用,前端基于 React + Vite + UnoCSS,后端基于 Nitro(h3)构建,内置 30 分钟缓存、GitHub OAuth 登录与跨设备数据同步、按来源更新频率自适应的抓取间隔,并原生支持 MCP(Model Context Protocol)Server 接入。本指南以仓库根目录的 README.md 为主线,结合 server 与 shared 目录的源码实现,完整讲解从零部署(Cloudflare Pages / Docker)、GitHub OAuth 与数据库配置、本地开发,到新增数据源抓取器的全流程,并深入剖析缓存与自适应抓取机制的底层代码逻辑。

说明:当前版本为 DEMO,仅支持中文内容;正式版将提供更好的定制化功能与英文内容支持(见 README.md 顶部 NOTE)。本指南所引用的路径均为当前仓库根目录下的相对路径。

核心功能特性

根据 README.md 的功能清单,并结合源码逐一印证:

  • 优雅的阅读界面:多专栏卡片式布局,顶部提供「更多 / 关注 / 最热 / 实时」等分类视图,支持来源搜索与自定义专栏(界面见 screenshots/preview-1.png、screenshots/preview-2.png)。
  • 实时获取最新热点新闻:内置数十个内容源抓取器,分布在 server/sources/ 目录,涵盖微博热搜、V2EX、知乎、IT 之家、财联社、Hacker News、GitHub Trending、联合早报等。
  • GitHub OAuth 登录与数据同步:登录后可将自定义的专栏元数据(PrimitiveMetadata)同步到服务端数据库,跨设备保持一致。
  • 默认 30 分钟缓存:缓存 TTL 定义于 shared/consts.ts,即TTL = 30 * 60 * 1000;登录用户可通过latest参数强制刷新获取最新数据。
  • 自适应抓取间隔(最快每 2 分钟):每个来源可在配置中声明自己的interval,避免频繁抓取导致 IP 被封禁(详见下文"缓存与自适应抓取机制")。
  • 支持 MCP Server:可将 NewsNow 作为 MCP Server 接入 Claude 等支持 MCP 的客户端。

缓存与自适应抓取机制的源码级解析

这是本项目最具技术价值的设计,值得先于部署深入理解。相关常量定义在 shared/consts.ts:

export const TTL = 30 * 60 * 1000 // 缓存过期时间(30 分钟) export const Interval = 10 * 60 * 1000 // 默认刷新间隔(10 分钟)

来源级自适应间隔

不同来源的内容更新频率差异巨大(热搜每分钟都在变,而部分博客可能一天才更新一次),因此 shared/pre-sources.ts 定义了五档间隔常量:

const Time = { Test: 1, // 测试用 Realtime: 2 * 60 * 1000, // 实时类,最快每 2 分钟 Fast: 5 * 60 * 1000, // 快速类,每 5 分钟 Default: Interval, // 默认 10 分钟 Common: 30 * 60 * 1000, // 常规类,每 30 分钟 Slow: 60 * 60 * 1000, // 慢速类,每 60 分钟 }

例如 shared/pre-sources.ts 中微博配置了interval: Time.Realtime(2 分钟),联合早报配置了interval: Time.Common(30 分钟)。该配置经过 scripts/source.ts 预处理后写入 shared/sources.json,供服务端运行时读取。

缓存表与读写

缓存底层是一个简单的 SQLite 风格数据表(通过db0访问,可平滑切换到 Cloudflare D1),实现在 server/database/cache.ts:

CREATE TABLE IF NOT EXISTS cache ( id TEXT PRIMARY KEY, updated INTEGER, data TEXT );

set用INSERT OR REPLACE写入序列化后的新闻数组并记录updated时间戳;getEntire还兼容了 Cloudflare D1 返回{ results: [] }结构的差异,说明该实现刻意适配了 CF Worker 环境。

命中缓存的判定逻辑

核心判定逻辑位于 server/api/s/index.ts,这也是对外提供单来源数据的GET /api/s?id=<sourceId>接口:

  1. 若now - cache.updated < sources[id].interval,直接返回缓存(status: "success")。注释明确说明:interval 是"刷新间隔",即使缓存未失效也要遵守,因为该来源本身内容更新就很慢;
  2. 若缓存已超过 interval 但仍在 TTL(30 分钟)内,则区分两种情况返回status: "cache":
    • 请求未带latest参数;
    • 请求带了latest,但服务器未配置登录,或用户未登录(匿名用户无法强制刷新,防止缓存被绕过导致对上游的频繁请求);
  3. 只有登录用户携带latest参数时,才会真正调用抓取器getters[id]()拉取最新数据,截取前 30 条(slice(0, 30))后回写缓存;
  4. 若抓取失败,则回退返回旧缓存;无缓存可回退时才抛出 500。

从源码结构可以推断,这一设计同时兼顾了上游站点压力控制(interval 限频 + TTL 复用 + 匿名用户不可强制刷新)与用户体验(登录用户可手动获取最新)。值得注意的一个细节是Date.now()在 Cloudflare Worker 整个运行期内不会更新,代码中也对此做了注释说明。

抓取器的统一入口

所有来源抓取器通过 glob 自动收集,见 server/getters.ts:import * as x from "glob:./sources/{*.ts,**/index.ts}",将每个文件导出的defineSource结果合并为一个getters映射,这也是新增数据源无需修改路由代码即可生效的原因。

接入 MCP Server

NewsNow 原生支持作为 MCP Server 被 Claude Desktop 等 MCP 客户端调用,配置方式直接取自 README.md,写入客户端的 MCP 配置文件中:

{ "mcpServers": { "newsnow": { "command": "npx", "args": [ "-y", "newsnow-mcp-server" ], "env": { "BASE_URL": "https://newsnow.busiyi.world" } } } }

npx -y newsnow-mcp-server会临时拉取并运行官方 MCP 服务端包,通过BASE_URL指定新闻数据接口的域名。部署到自己的域名后,请将BASE_URL替换为你的域名,例如https://your-domain.com,这样 LLM 便能通过 MCP 协议实时检索你部署实例上的热点新闻。

部署指南

基础部署(无需登录与缓存)

如果不需要登录、同步和缓存功能,这是最快的上线方式:

  1. Fork 本仓库;
  2. 导入到 Cloudflare Pages 或 Vercel 等平台,平台会自动识别构建配置。

Cloudflare Pages 配置

在 Cloudflare Pages 的项目设置中填写:

  • 构建命令:pnpm run build
  • 输出目录:dist/output/public

build脚本定义在 package.json:"build": "npm run presource && vite build",其中presource会先执行 scripts/favicon.ts 与 scripts/source.ts 生成图标清单和来源配置文件,再执行 Vite 构建(配合vite-plugin-with-nitro输出 Nitro 服务端产物)。

GitHub OAuth 配置

开启登录功能前,需要先创建 GitHub OAuth 应用:

  1. 在 GitHub 的 Applications 页面创建一个 GitHub App(无需申请任何特殊权限);
  2. 回调 URL 设置为:https://your-domain.com/api/oauth/github(将your-domain替换为实际域名);
  3. 获取 Client ID 和 Client Secret,填入下方环境变量。

登录的完整实现见 server/api/oauth/github.ts:服务端用code换取 access_token 后请求 GitHub 用户信息,将用户写入user表,再使用jose的SignJWT签发 60 天有效期的 HS256 JWT(payload 含id与type: "github"),最后重定向回首页并把jwt与用户头像昵称以 query 参数带回前端。Nitro 在 Cloudflare 环境设置 Cookie 存在已知问题,因此代码采用 URL 参数方式传递(源码中有对应注释)。

环境变量配置

本地运行时参考 example.env.server,将其重命名为.env.server并填写:

# Github Client ID G_CLIENT_ID= # Github Client Secret G_CLIENT_SECRET= # JWT Secret, 通常就用 Client Secret JWT_SECRET= # 初始化数据库, 首次运行必须设置为 true,之后可以将其关闭 INIT_TABLE=true # 是否启用缓存 ENABLE_CACHE=true

各变量的实际用途与源码对应关系如下:

  • G_CLIENT_ID/G_CLIENT_SECRET:GitHub OAuth 凭证,在 server/api/oauth/github.ts 中用于换取 access_token;
  • JWT_SECRET:登录态签名密钥,server/api/oauth/github.ts 用它签发 JWT,server/middleware/auth.ts 用jwtVerify校验请求头Authorization: Bearer <token>并写入event.context.user。从 server/middleware/auth.ts 可看到:若未配置这三个变量,服务端会禁用登录并对/api/me等需要认证的接口返回 506;若 JWT 校验失败,访问/api/me会返回 401;
  • INIT_TABLE:首次运行必须为true,用于自动建表(cache表见 server/database/cache.ts,user表见 server/database/user.ts),初始化成功后建议关闭;
  • ENABLE_CACHE:是否启用缓存,关闭时 server/database/cache.ts 的getCacheTable()会直接返回空;
  • PRODUCTHUNT_API_TOKEN(额外变量):example.env.server 中还存在该变量,供 Product Hunt 等需要 token 的来源抓取使用,可按需填写。

数据库支持

本项目通过db0统一访问数据库,支持其全部 connector(可在 db0 官方 connectors 文档中查询,本项目主推 Cloudflare Pages 与 Docker 部署,Vercel 需自行搞定数据库)。官方推荐使用 Cloudflare D1。

以 D1 为例,配置步骤:

  1. 在 Cloudflare Worker 控制面板创建 D1 数据库;
  2. 在wrangler.toml中配置database_id和database_name;
  3. 若仓库中没有wrangler.toml,可将 example.wrangler.toml 重命名并修改配置,其模板为:
name = "newsnow" pages_build_output_dir = "dist/output/public" compatibility_date = "2024-10-03" [[d1_databases]] binding = "NEWSNOW_DB" database_name = "newsnow-db" database_id = ""
  1. 重新部署即可生效。

Docker 部署

对于 Docker 部署,只需使用项目根目录的 docker-compose.yml,在项目根目录执行:

docker compose up

镜像为ghcr.io/ourongxing/newsnow:latest,默认映射宿主机4444端口,并通过命名卷newsnow_data持久化数据库数据。同样可以通过docker-compose.yml中的environment段配置G_CLIENT_ID、G_CLIENT_SECRET、JWT_SECRET、INIT_TABLE、ENABLE_CACHE、PRODUCTHUNT_API_TOKEN等环境变量(模板中已预留这些字段)。

本地开发

前提:需要 Node.js >= 20。

corepack enable pnpm i pnpm dev
  • corepack enable启用包管理器(仓库通过 package.json 固定了packageManager: pnpm@10.30.3);
  • pnpm i安装依赖(注意:项目对dayjs应用了补丁 patches/dayjs.patch,并在pnpm.overrides中锁定了h3、nitropack等关键依赖版本,请勿随意改动);
  • pnpm dev启动开发服务器,命令为npm run presource && cross-env NODE_OPTIONS=--use-env-proxy vite dev,会先执行预处理脚本再启动 Vite(含 Nitro 服务端)。

其他常用脚本(见 package.json):

  • pnpm build:生产构建,产物位于dist/output/public;
  • pnpm start:node --env-file .env.server dist/output/server/index.mjs,以本地 Node 方式运行构建产物(需.env.server);
  • pnpm test:运行vitest测试,现有测试见 server/utils/date.test.ts 与 test/common.test.ts;
  • pnpm typecheck:分别对 Node 侧与 App 侧执行tsc --noEmit类型检查;
  • pnpm preview/pnpm deploy:在CF_PAGES=1下构建并用 wrangler 本地预览 / 部署到 Cloudflare Pages。

添加新数据源

README 明确说明:添加数据源请关注shared/sources(即 shared 目录下的来源配置,核心为 shared/pre-sources.ts)与 server/sources/ 目录,项目类型完备、结构简单。详细的逐步教程见 CONTRIBUTING.md,核心流程如下:

1. 注册来源配置

在 shared/pre-sources.ts 中注册来源。若给已有来源添加子来源(如给 Bilibili 增加"热门视频"),在其sub字段下新增子项;若是全新来源,则新增顶层条目:

"newsource": { name: "New Source", color: "blue", home: "https://www.example.com", column: "tech", // 选择合适专栏 type: "hottest" // 或 "realtime" }

可选字段还包括interval(刷新间隔,默认 10 分钟)、desc、disable等,完整定义见 shared/types.ts 中的Source接口。

2. 实现抓取器

在 server/sources/ 目录下新建或修改文件(如newsource.ts),使用项目提供的defineSource与myFetch辅助函数。myFetch定义于 server/utils/fetch.ts,内置了浏览器 UA、10 秒超时与 3 次重试,可显著降低被上游站点拒绝的概率。以 GitHub Trending 抓取器 server/sources/github.ts 为例:

const trending = defineSource(async () => { const html: any = await myFetch("https://github.com/trending?spoken_language_code=") const $ = cheerio.load(html) const news: NewsItem[] = [] // ... 解析 DOM 并构造 NewsItem return news }) export default defineSource({ "github": trending, "github-trending-today": trending, })

一个来源可同时导出多个 source id(如github与github-trending-today共用同一抓取逻辑),defineSource的聚合逻辑见 server/getters.ts。返回的数据必须符合NewsItem结构(定义于 shared/types.ts):

interface NewsItem { id: string | number // 唯一标识 title: string // 标题 url: string // 原文链接 mobileUrl?: string // 可选:移动端链接 pubDate?: number | string // 可选:发布时间 extra?: { hover?: string // 悬停提示文本 date?: number | string // 格式化日期 info?: false | string // 附加信息(如"✰ 12.3k") diff?: number // 时间差 icon?: false | string | { url: string; scale: number } // 图标 } }

3. 重新生成来源文件

修改配置或抓取器后,运行:

npm run presource

该命令会重新生成 shared/sources.json 等产物文件,使新来源在前端与GET /api/s接口中生效。

4. 测试与提交

启动pnpm dev后在浏览器中确认新来源正常展示,然后提交变更并创建 Pull Request(git checkout -b feature-name→git commit→git push origin feature-name)。注意:README 的贡献章节已声明,当前版本即将被新版取代,暂时不再接受外部贡献,此流程仅供理解架构与自行扩展参考。

GitHub 登录与数据同步机制

登录态的完整链路可以概括为:GitHub OAuth 换取 JWT → 前端存储 → 请求携带 Bearer Token → 中间件校验 → 读写用户数据表。

  • 登录触发:server/api/login.ts 负责发起 OAuth 跳转,server/api/oauth/github.ts 处理回调并签发 JWT(有效期 60 天);
  • 认证校验:server/middleware/auth.ts 对所有/api/*路径生效,对/api/s、/api/me解析Authorization头中的 JWT 并注入event.context.user;未配置密钥时对非白名单接口返回 506;
  • 用户存储:server/database/user.ts 维护user表(id、email、data、type、created、updated),addUser支持幂等插入,setData/getData用于读写用户的自定义专栏元数据;
  • 同步接口:server/api/me/sync.ts 提供GET /api/me/sync(拉取同步数据)与POST /api/me/sync(写入同步数据,服务端会调用verifyPrimitiveMetadata校验结构),前端对应的状态管理见 src/atoms/primitiveMetadataAtom.ts 与 hooks 目录下的 useSync.ts。

路线图与扩展方向

根据 README.md 的 Roadmap,项目后续计划包括:

  • 添加多语言支持(英语、中文,更多语言即将推出);
  • 改进个性化选项(基于分类的新闻、保存的偏好设置);
  • 扩展数据源以覆盖多种语言的全球新闻。

开源协议

本项目基于 MIT 协议开源,版权归 © ourongxing 所有。

  • 前端
  • 后端
  • 网页爬虫

【免费下载链接】newsnow

Elegant reading of real-time and hottest news

项目地址:https://gitcode.com/GitHub_Trending/ne/newsnow
点击查看免费下载
上一篇:【亲测免费】 Intouch驱动_DAServer_DASSIDirect3.0:工业自动化通讯的强大助力
下一篇:Ethereal Style for Zotero:从混乱到有序,文献管理的新范式

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 1:52:37

mdBook 通用配置指南:book.toml 中的 book、rust 与 build 配置项详解

开发工具文档 【免费下载链接】mdBook Create book from markdown files. Like Gitbook but implemented in Rust 项目地址&#xff1a; https://gitcode.com/gh_mirrors/md/mdBook 点击查看 免费下载 mdBook 将一本书的全部构建参数集中存放在根目录的 book.toml 文件中&…

作者头像 李华
网站建设 2026/10/1 1:52:12

《UDS协议从入门到精通》系列——图解0x14:清除诊断信息

《UDS协议从入门到精通》系列——图解0x14:清除诊断信息 一、简介 二、数据包格式 2.1 服务请求格式 2.2 服务响应格式 2.2.1 肯定响应 2.2.2 否定响应 三、通信示例 Tip📌:本文描述中但凡涉及到其他UDS服务的,均提供专栏内文章链接跳转方式以便快速了解他们。 学习UDS基础…

作者头像 李华
网站建设 2026/10/1 1:51:14

redis基础(一)数据类型与常用命令

redis都是键值对形式&#xff0c;常用类型有5种&#xff1a;String、List、Set、Zset、Hash&#xff0c;这5种类型说的是键值对中值的类型&#xff0c;所有的键都是String型。本文主要介绍 Redis 最经典的五种基础数据结构&#xff0c;Redis 后续版本还提供了 Stream、GEO、Bit…

作者头像 李华
网站建设 2026/10/1 1:50:07

被太阳烤出来的马德拉酒:工艺、选酒与餐搭指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华