☰
QOwnNotes Homepage 书签建议 API 接入指南:为 Homepage 搜索框提供本地书签联想
2026/10/12 11:19:09 网站建设 项目流程
  • 桌面应用

【免费下载链接】QOwnNotes

QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.

项目地址:https://gitcode.com/gh_mirrors/qo/QOwnNotes
点击查看免费下载

QOwnNotes 内置了一个面向 Homepage 仪表盘的本地 HTTP 建议接口(Bookmark Suggestion API),它复用 Web Companion 浏览器扩展同款的书签解析与索引逻辑,让 Homepage 的搜索框可以直接从你本地笔记中的书签生成联想建议。本文将从启用配置、HTTP 端点协议、书签匹配算法、Homepage 配置,到仓库自带的custom.js/custom.css前端整合方案,给出完整可落地的接入教程。

功能概述:一条命令连通「本地书签」与「Homepage 搜索」

QOwnNotes 以纯文本 Markdown 文件存储笔记,而书签正是以 Markdown 链接形式存在于笔记中。Homepage Suggestion API 的核心思路是:

  1. QOwnNotes 在本地启动一个仅绑定127.0.0.1的 HTTP 服务;
  2. Homepage(或其custom.js前端脚本)向该服务请求GET /suggest?q=<关键字>;
  3. QOwnNotes 扫描带bookmarks标签的笔记、名为Bookmarks的笔记以及当前打开的笔记,解析出书签后返回 JSON 建议列表;
  4. Homepage 将建议合并进自己的搜索联想框,点击后可直接打开书签 URL,而不是交给搜索引擎。

这意味着你的 Homepage 搜索框从此拥有了「个人书签搜索引擎」能力,数据完全保留在本机,无需上传任何云端。

在 QOwnNotes 中启用 Bookmark Suggestion API

设置入口

打开 QOwnNotes 的Settings -> Browser extension / command snippets(Web Companion 设置页),按以下步骤操作:

  1. 勾选Enable socket server(启用 Socket 服务),这是 Suggestion API 生效的前置开关——未启用时整个浏览器扩展框架区都是灰的;
  2. 在Bookmark suggestion API分组框中勾选Enable Homepage-compatible bookmark suggestions API;
  3. 设置一个监听端口(默认为22224);
  4. 可选:设置一个安全令牌(Security token)。

对应界面定义可以在 webcompanionsettingswidget.ui 中看到:端口使用QSpinBox(取值范围 1~65535,默认 22224),令牌使用QLineEdit(echoMode为 Password,最大长度 32),并附带三个工具按钮:显示令牌、复制到剪贴板、重新生成令牌。设置读取/存储逻辑位于 webcompanionsettingswidget.cpp。

底层参数说明

这些设置最终映射到SettingsService的配置键,由 websocketserverservice.cpp 读取:

配置键默认值说明
webSocketServerService/bookmarkSuggestionApiEnabledfalse是否启用建议 API,对应 isBookmarkSuggestionApiEnabled()
webSocketServerService/bookmarkSuggestionApiPort22224(Debug 构建为22225)监听端口,对应 getBookmarkSuggestionApiDefaultPort()
webSocketServerService/bookmarkSuggestionApiToken自动生成 32 位随机串访问令牌,通过CryptoService加密存储,见 getOrGenerateBookmarkSuggestionApiToken()

几个值得注意的实现细节:

  • 仅绑定本机回环地址:HTTP 服务通过m_pHttpServer->listen(QHostAddress::LocalHost, port)启动(startSuggestionHttpServer()),不会暴露到局域网,外部机器无法直接访问。
  • 令牌自动生成与加密:保存设置时若令牌为空,会自动生成一个 32 位随机字符串;令牌在设置文件中以加密形式保存(见 webcompanionsettingswidget.cpp)。同时代码保留了对旧版明文值的兼容回退逻辑,读取时会自动迁移为加密存储。
  • 服务联动:refreshServers()会在启用开关打开时启动 HTTP 服务、关闭时停止(websocketserverservice.cpp),与 WebSocket 服务相互独立、互不影响。

HTTP 端点协议详解

请求格式

  • 端点:GET /suggest
  • 查询参数:
参数必选说明
q是搜索关键字,URL 编码后传入
limit否返回建议条数上限,默认10,最小1,最大50
token否安全令牌;仅在 QOwnNotes 中配置了令牌后必须携带

响应格式

响应为 JSON 数组,第一个元素是原始查询字符串,第二个元素是建议字符串数组:

["home", ["Homepage", "https://example.com/home", "Some Home Link"]]

该结构的序列化逻辑在 Bookmark::homepageSuggestionResponseJson() 中实现:数组第一个元素为查询词,第二个元素为建议列表。

错误状态码与请求处理流程

请求处理在 processHttpRequest() 中完成,顺序如下:

  1. 请求行解析失败 → 返回400 Bad Request;
  2. 非GET方法 → 返回405 Method Not Allowed;
  3. 路径不是/suggest→ 返回404 Not Found;
  4. token参数与配置的令牌不一致 → 返回401 Unauthorized(未配置令牌时则跳过该校验);
  5. limit参数非法时回退为10,超出 1~50 范围时被强制收敛到边界;
  6. 正常时返回200 OK与 JSON 响应体。

此外,所有响应都带有 CORS 头(Access-Control-Allow-Origin: *)、Cache-Control: no-store与Connection: close(见 httpResponse()),方便浏览器端脚本跨域请求。

性能优化:双层缓存

服务端实现了两级缓存(homepageSuggestionResponse()):

  • 书签缓存:书签列表缓存 2500ms(2.5 秒)后失效重建,避免每次请求都重新解析所有笔记;
  • 建议结果缓存:以查询词|limit为键缓存生成好的 JSON 响应,缓存上限 200 条,超出后按插入顺序淘汰最旧条目。

书签来源与匹配算法(源码级解析)

书签从哪里来

getBookmarksForSuggestions()(websocketserverservice.cpp)按以下顺序汇总书签:

  1. 所有带有bookmarks标签的笔记(标签名可在设置中修改,默认bookmarks,见 getBookmarksTag());
  2. 所有名为Bookmarks的笔记(笔记名同样可配置,默认Bookmarks,见 getBookmarksNoteName());
  3. 当前正在编辑的笔记中的所有链接。

汇总前会做去重合并(相同 URL 的书签合并标签、名称与描述),然后整体缓存。

书签如何解析

Bookmark::parseBookmarks() 使用正则解析笔记文本,支持三类 Markdown 链接:

  • 标准书签格式:- [名称](http://链接) #标签1 #标签2 描述文字(行首为-或*);
  • 普通命名链接:[名称](http://链接);
  • 尖括号链接:<http://链接>。

其中 URL 必须以协议://形式出现(如https://、http://)。

建议匹配与排序

Bookmark::suggestionStrings() 实现了完整的匹配算法:

  • 大小写不敏感:查询词与书签的名称、URL、标签、描述、原始 Markdown 文本统一转为小写后比较;
  • 多词 token 匹配:查询词按空格拆分为多个 token,书签必须包含所有token 才算命中(token 顺序无关);
  • 前缀优先排序:名称或 URL 以查询词/任一 token 开头的书签排在前面,其次才是仅包含子串的书签;
  • 输出配对:命中书签会先输出名称、再输出 URL(测试用例 testBookmarkSuggestionsKeepNameUrlPairing 明确验证了「名称索引 < URL 索引」的顺序),这正是custom.js建立「名称→URL」映射的前提;
  • 去重:大小写折叠后相同的建议只保留一条(testBookmarkSuggestionsDeduplication)。

仓库单元测试 test_notes.cpp 覆盖了前缀/子串匹配、去重、多 token 顺序无关、名称-URL 配对、元数据(标签/描述)参与匹配、空查询、limit 收敛(limit=100时强制为 50)以及响应 JSON 结构等全部关键行为,可作为你理解算法边界的参考。

配置 Homepage:让搜索框接收本地建议

搜索配置示例

在 Homepage 的配置中,为search块指定provider: custom,并将suggestionUrl指向本地 QOwnNotes 建议接口:

search: provider: custom url: https://example.com/search?q= suggestionUrl: http://127.0.0.1:22224/suggest?q= showSearchSuggestions: true
  • provider: custom:告诉 Homepage 使用自定义搜索提供方;
  • suggestionUrl:Homepage 会向该地址追加用户输入的查询词并发起联想请求,showSearchSuggestions: true启用联想框显示;
  • 若你在 QOwnNotes 中配置了安全令牌,请保持suggestionUrl不变,改由custom.js中的QON_TOKEN变量在请求时自动追加&token=...,见下文。

需要修改哪个 Homepage 文件

在标准 Homepage 安装中,将search块加入以下任一文件:

  • settings.yaml(Homepage 全局设置)
  • settings.yml(同上,取决于你的安装命名)
  • 容器中挂载为/app/config/settings.yaml的文件

如果你的 Homepage 部署把配置拆分到多个文件,请编辑已经包含searchprovider 设置的那个文件,而不要新建重复配置。

自定义 Homepage 前端资源:合并建议与直接打开书签

仅配置suggestionUrl时,Homepage 会把建议当作普通搜索词。若希望建议直接打开书签 URL(而非跳转搜索引擎),需要使用仓库自带的定制前端资源。

资源位置

仓库在 docs/homepage 目录下提供了现成的定制示例:

  • custom.js:核心整合脚本;
  • custom.css:为 QOwnNotes 建议条目提供视觉区分样式;
  • README.md:整合说明文档。

当你的 Homepage 部署支持加载custom.js与custom.css时,将这两个文件放入对应目录即可。

custom.js 的工作原理

custom.js是一个立即执行的前端脚本,逐条完成了以下工作(对应 docs/homepage/README.md 的说明):

  1. 拦截建议请求:重写window.fetch,拦截 Homepage 的/api/search/searchSuggestion端点请求;
  2. 合并建议:额外向 QOwnNotes 的http://127.0.0.1:22224/suggest?q=<查询>&limit=<QON_LIMIT>发起请求,并把返回的建议与 Homepage 原生建议合并(去重后返回,QOwnNotes 建议排前);
  3. 标记来源:为每条 QOwnNotes 建议添加[QON]前缀(QON_LABEL),在界面上一眼可辨;
  4. 建立名称→URL 映射:将「名称 + URL」成对出现的建议存入suggestionToUrl映射表;
  5. 拦截新窗口打开:重写window.open,识别搜索引擎跳转 URL 并解码出原始书签地址,若命中映射表则直接以书签 URL 打开新标签页,避免把书签文本交给搜索引擎;带[QON]前缀的文本会被彻底拦截,绝不外泄给搜索服务;
  6. 破除 4 条截断:通过改写Response.prototype.json,拦截 Homepage 对建议列表「前 4 条」的客户端裁剪逻辑,让合并后的完整建议列表得以展示;
  7. DOM 标记:通过MutationObserver为匹配行添加qon-suggestionCSS 类,并处理键盘导航、滚动定位、URL 提示行等细节。

可调参数

custom.js顶部的常量即全部配置开关:

常量默认值说明
QON_URLhttp://127.0.0.1:22224/suggest?q=QOwnNotes 建议接口地址
QON_TOKEN""与 QOwnNotes 设置中相同的安全令牌;配置后请求会自动追加&token=...
QON_LIMIT20向 QOwnNotes 请求的建议条数(上限受服务端 50 限制)
QON_LABEL"[QON] "显示在建议前的标记文本
DEBUGfalse设为true可输出[QON-MERGE]调试日志

custom.css 的样式效果

custom.css 为button.qon-suggestion添加绿色(#2f855a)左边框和文字颜色,并针对映射到 URL 的建议行(li.qon-li-has-url)在下方渲染一个小字号 URL 提示(.qon-url-hint),方便你确认即将打开的地址。

外部主机部署时的注意点

如果你的 Homepage 运行在与 QOwnNotes 不同的机器/容器上,必须:

  1. 将custom.js与custom.css部署到承载 Homepage 的那台主机上,它才能跨机查询 QOwnNotes 的建议接口;
  2. 使用 QOwnNotes 安全令牌时,确保custom.js内的QON_TOKEN与 QOwnNotes 设置中的令牌一致。

安全边界与生产建议

由于书签数据可能包含敏感 URL,官方文档明确提示了以下安全边界:

  • 默认仅限本机访问:服务只绑定127.0.0.1,外部网络无法直接触达;
  • 必须使用安全令牌:令牌校验失败返回401,未配置令牌时接口对所有本机进程开放;建议始终配置令牌;
  • 如需跨机访问:应在 QOwnNotes 之前放置反向代理,并用防火墙规则或 IP 白名单限制访问来源,不要直接将端口暴露到公网;
  • 令牌加密存储:令牌通过CryptoService加密后写入设置,避免明文落盘(相关键也被纳入 misc.cpp 的敏感键清单)。

验证与排错

启用并配置完成后,你可以直接在本机用curl验证接口:

# 不带令牌 curl "http://127.0.0.1:22224/suggest?q=home&limit=10" # 带令牌(替换为你的实际令牌) curl "http://127.0.0.1:22224/suggest?q=home&limit=10&token=YOUR_TOKEN"

期望返回形如["home",["Homepage","https://example.com/home"]]的 JSON。若返回401,请核对custom.js中的QON_TOKEN与 QOwnNotes 设置中的令牌是否一致;若返回404,请确认请求路径为/suggest且 QOwnNotes 的启用开关与 Socket server 开关均已打开。更新custom.js/custom.css后,请对 Homepage 页面执行硬刷新,确保浏览器加载新版本脚本。

至此,你的 Homepage 搜索框已经与本地书签笔记打通:输入关键字即可获得来自 QOwnNotes 笔记的个人化联想建议,并直接打开对应书签,全程数据不出本机。

  • 桌面应用

【免费下载链接】QOwnNotes

QOwnNotes is a plain-text file notepad and todo-list manager with Markdown support and Nextcloud / ownCloud integration.

项目地址:https://gitcode.com/gh_mirrors/qo/QOwnNotes
点击查看免费下载

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询