news 2026/9/11 14:22:35

qBittorrent 如何编写调用 WebUI 的客户端并适配 API 变化?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
qBittorrent 如何编写调用 WebUI 的客户端并适配 API 变化?

qBittorrent 如何编写调用 WebUI 的客户端并适配 API 变化?

【免费下载链接】qBittorrentqBittorrent BitTorrent client项目地址: https://gitcode.com/GitHub_Trending/qb/qBittorrent

你遇到的任务是:写一个脚本或程序,通过 qBittorrent 的 WebAPI 完成添加种子、同步状态、控制会话等操作,并且希望在 qBittorrent 升级后能快速发现并修复 WebAPI 的破坏性变化。完成这篇文章后,你会有一条从「验证服务可达 → 建立认证 → 拉取数据 → 执行写操作 → 对照 changelog 适配变更」的连续路径。前提是你已经安装并启动了 qBittorrent 且开启了 WebUI(默认端口 8080,见 Preferences 默认值),并知道 WebUI 的登录账号密码。

WebAPI 的暴露方式与版本查询

所有接口都挂在基础路径/api/v2/下(webapplication.cpp 中API_PATH = u"/api/v2/"_s),请求形如http://<主机>:8080/api/v2/<scope>/<action>,例如api/v2/torrents/info

两个版本接口要区分开:

  • app/version:返回 qBittorrent 程序版本号(appcontroller.cpp 中返回QBT_VERSION);
  • app/webapiVersion:返回 WebAPI 自身的版本号,当前仓库中该常量定义为2.16.2(webapplication.h 中API_VERSION {2, 16, 2})。适配 API 变化时你真正需要比对的是后者。

auth/login被声明为公开接口(webapplication.cpp 中declarePublicAPI(u"auth/login"...))外,访问其他端点时如果没有有效会话,会直接收到 403。所以客户端的第一步永远是先认证。

认证方式一:用户名密码登录并持有会话 Cookie

WebUI 自带的登录脚本就是 WebAPI 调用的参照实现:以表单编码 POSTusernamepasswordauth/login(login.js)。服务端校验通过后建立会话并在响应中下发一个 httpOnly 的会话 Cookie,名称前缀为QBT_SID_(webapplication.cpp)。凭据无效时返回 401。

用 curl 验证这条路径(把USERPASS替换为你的 WebUI 账号密码,127.0.0.1:8080替换为实际地址端口):

# 登录,成功时返回 200,并把会话 Cookie 写入 cookies.txt curl -c cookies.txt \ -d "username=USER" -d "password=PASS" \ http://127.0.0.1:8080/api/v2/auth/login # 后续请求携带 Cookie;若凭据错误,第一步会收到 401 curl -b cookies.txt http://127.0.0.1:8080/api/v2/app/version

客户端需要长期保存并复用这个 Cookie:会话在服务端有超时,Cookie 过期后服务端会丢弃该会话(webapplication.cpp 中cookieSessionInitialize对过期会话直接删除)。另一个可选方式:自 2.15.0 起,WebAPI 凭据可以直接通过 HTTP Basic auth 提供,curl 写作curl -u USER:PASS http://127.0.0.1:8080/api/v2/app/version,无需先调用auth/login

注意 CSRF 保护默认开启:非 API Key 的跨站请求会被拒绝为 401(webapplication.cpp 中的isCrossSiteRequest检查)。对 curl/脚本这类不带Origin/Referer头的客户端,服务端按宽松策略放行;但如果你要从浏览器页面跨站调用,必须改用 API Key。

认证方式二:API Key(推荐用于长期运行的客户端)

自 2.14.1 起新增了app/rotateAPIKey(生成并轮换 API Key)和app/deleteAPIKey(删除现有 Key)。先登录,再调用app/rotateAPIKey

# 需要已登录的 Cookie;响应为 JSON:{"apiKey": "<生成的 Key>"} curl -b cookies.txt -X POST http://127.0.0.1:8080/api/v2/app/rotateAPIKey

之后的每个请求携带Authorization: Bearer头即可,不再依赖 Cookie 会话:

# 将 <apiKey> 替换为上一步响应 JSON 中的 apiKey 字段值 curl -H "Authorization: Bearer <apiKey>" http://127.0.0.1:8080/api/v2/sync/maindata

API Key 行为有两处与 Cookie 会话不同(webapplication.cpp):

  • 使用Bearer认证时跳过 CSRF 检查;
  • 使用Bearer认证访问auth/*端点会返回 403——API Key 会话不需要也不允许再走登录/登出。

如果服务端从未配置过 Key,app/rotateAPIKey的调用仍会生效(它生成并写入新 Key);Key 会保存到偏好项web_ui_api_key(appcontroller.cpp),也可以在 WebUI 偏好界面查看/轮换。

拉取数据:sync/maindata 与 rid 增量机制

状态同步主接口是sync/maindata,它通过rid(response id)实现增量更新(synccontroller.cpp):

# 首次调用不带 rid,返回完整快照(full_update 为 true)及一个 rid curl -b cookies.txt "http://127.0.0.1:8080/api/v2/sync/maindata" # 之后把上一次响应中的 rid 作为查询参数传回,只获取增量 curl -b cookies.txt "http://127.0.0.1:8080/api/v2/sync/maindata?rid=上次返回的rid"

响应包含full_updaterid以及torrentscategoriestagstrackersserver_state等字段(键定义见 synccontroller.cpp)。WebUI 自身客户端的写法可作参照:请求带cache: "no-store",每次从响应中取出新的rid用于下一次轮询(client.js 中syncMainData)。你的客户端应实现同样的循环:记录rid→ 轮询 → 更新本地状态 → 若full_update为 true 则整体重建。

执行写操作:先约定好状态码语义

写操作集中在torrents/*transfer/*app/setPreferences等端点,参数以表单字段或查询参数传递。以下状态码约定是客户端必须处理的,都来自 WebAPI_Changelog.md:

场景行为版本
torrents/add响应包含success_countpending_countfailure_countadded_torrent_idspending_count非零时返回 202,全部失败时返回 4092.14.0+
响应体无数据返回204 No Content(部分端点过渡期仍返回 200 OK)2.11.8+
端点不存在错误消息为Endpoint does not exist,用于区别于普通的 4042.14.0+
auth/login凭据无效返回 4012.14.0+
torrents/editTracker成功时固定返回 2042.13.0+

客户端不要假设所有成功都是 200,也不要把所有 204 当成失败。以torrents/add为例,一个健壮的判断顺序是:先读状态码(202 表示部分待处理、409 表示全部失败),再解析响应体中的计数字段。

适配 API 变化:版本号对照 changelog

客户端在启动或每次部署后,应先用认证后的会话请求app/webapiVersion,把返回值与 WebAPI_Changelog.md 中你当前支持版本之后的条目逐一比对。以下是 changelog 中与「客户端兼容性」直接相关的破坏性变化(每条均可在 changelog 中按 PR 号核对):

  • 2.16.0search/downloadTorrentrss/setFeedRefreshInterval改为仅接受 POST;torrents/add新增seedMode(bool) 参数,且不再接受skip_checking参数。如果你的客户端还在发skip_checking,升级后该参数会被忽略,应切换到seedMode
  • 2.16.2:新增rss/exportRulesrss/importRules(仅 POST);新增transfer/pauseSessiontransfer/resumeSessionsync/maindataserver_state中新增session_state(bool) 字段——依赖server_state结构的代码要注意新字段的出现。
  • 2.14.0torrents/add引入上表所述的计数字段与 202/409 状态码;不存在的端点开始返回Endpoint does not exist文案。
  • 2.13.0torrents/editTracker的参数origUrl更名为url,旧参数名不再可用。
  • 2.15.0:起可用 Basic auth 提供凭据(对旧客户端是可选的新路径,不是破坏项)。

排查方向可以由状态码反推:401 优先检查凭据或跨站来源;403 检查会话是否过期、是否在用 API Key 访问auth/*;405 Method Not Allowed 通常意味着该端点已改为仅 POST(对照 2.16.0/2.16.2 条目);收到Endpoint does not exist则说明端点被移除或更名,回 changelog 找对应版本的替换项。

限制与边界

  • 公开端点只有auth/login,其余全部依赖会话;用 API Key 认证时auth/*端点被禁止(403)。
  • 会话 Cookie 有服务端超时,客户端需要处理 Cookie 失效后重新登录的分支。
  • 各版本新增的参数(如torrents/addseedModesync/maindatasession_state)只在对应版本起可用,跨版本部署的客户端应以app/webapiVersion的返回值决定行为分支。

【免费下载链接】qBittorrentqBittorrent BitTorrent client项目地址: https://gitcode.com/GitHub_Trending/qb/qBittorrent

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

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

STM32寄存器操作实战指南:从GPIO到NVIC的23个关键寄存器

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

作者头像 李华
网站建设 2026/9/11 14:20:41

CesiumJS 自定义 Widget 快速上手:Cesium Viewer 控件扩展完整指南

CesiumJS 自定义 Widget 快速上手&#xff1a;Cesium Viewer 控件扩展完整指南 【免费下载链接】cesium An open-source JavaScript library for world-class 3D globes and maps :earth_americas: 项目地址: https://gitcode.com/GitHub_Trending/ce/cesium CesiumJS 自…

作者头像 李华
网站建设 2026/9/11 14:17:53

C++模板深度解析:非类型参数与分离编译实战

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

作者头像 李华
网站建设 2026/9/11 14:17:51

虚拟货币微交易系统源码拆解:K线控制与代理分销实现

开始做技术这么些年&#xff0c;接手的项目五花八门&#xff0c;但凡是带着"理财、交易、行情"这几个词的系统&#xff0c;基本都有个共性——前端要好看&#xff0c;后端要扛得住&#xff0c;中间还夹着一堆代理分账的逻辑。这次拆解的这套"虚拟货币微交易投资…

作者头像 李华