DSH plugin 注册 WebRoute:匹配顺序、fallback 席位与 index 挂接点

插件开发发布于 2026-10-17作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSH pluginWebRoutefallbackindex 注入HTTP
DSH plugin 怎么往 Host 的 HTTP 载体注册路由:exact 与 prefix 的匹配顺序、唯一的 fallback 席位、index 注入的两种挂接点,以及监听失败与拆卸语义。

DSH plugin 的 HTTP 载体刻意「什么都不懂」:它不理解任何 Harness 概念,只提供命名路由、可选的 gzip、index 转换回调和一个可认领的回退处理器。 所有功能路由——/api 桥接、插件 bundle、HMR 事件流——都由别的插件注册。这个定位带来三个必须记住的规则:匹配顺序固定为 exact → 最长前缀 → fallback,注册顺序不携带语义;fallback 只有一个所有者;它只服务浏览器(Electron 走 file:// 加 IPC,不经过它)。

DSH plugin 的 HTTP 载体:只管浏览器,不碰业务

一句话结论:载体提供传输能力,功能路由全由插件注册;它不属于 agent loop,也不是能力 seam。

  1. 本体:一个提供 ctx.webServer 的 node:http 插件。
  2. 包含什么:具名路由注册表、可选 gzip、index 转换回调、可认领的回退。
  3. 不包含什么:TLS、认证、Origin 策略都不在载体里。
  4. 服务对象:只服务浏览器;桌面端用 file:// 与 IPC,不用这个服务器。
  5. 输出归属:包本身不打印任何东西,启动 URL 行归 shell 所有。

DSH plugin 的 WebRoute 与匹配顺序:exact → 最长前缀 → fallback

一句话结论:匹配顺序固定,注册顺序不参与请求语义。

ts
interface WebRoute {
  kind: 'exact' | 'prefix'
  path: string   // 绝对路径名,无尾斜杠
  handler: (req, res) => void | Promise<void>
}
  1. exact:逐字匹配路径名。
  2. prefix:匹配该前缀及其下任意子路径。
  3. 顺序:先 exact 表,再最长匹配前缀,最后 fallback。
  4. 互不相交:具名路由在组合上必须互不重叠,重复的 (kind, path) 直接抛错。
  5. upgrade 路由:同一路径只能有一个协议所有者,重复注册同样抛错。
  6. handler 职责:拥有完整响应生命周期,可以像 SSE 那样把连接一直开着。

DSH plugin 的 fallback 席位:只能有一个所有者

一句话结论:回退处理器唯一,第二次注册抛错;未认领的请求在启动期返回 404。

  1. 语义:应答所有未被命名路由匹配的请求。
  2. 唯一性:两个回退无法组合,因此只允许一个所有者。
  3. 随产品交付的认领者:前端静态插件认领席位,提供 SPA dist 的固定语义。
  4. 静态语义细节:读取 dist 前先完成认证;非 index 资产公开;非 GET/HEAD 返回 405;越出根目录返回 403;缺失返回空 404;未知扩展名按 octet-stream。
  5. 启动期:席位未被认领时,未匹配请求按 404 应答,直到所有者注册。

DSH plugin 的 index 挂接:结构化注入与原始 tap

一句话结论:先渲染结构化注入行,再按注册顺序应用原始 html 转换。

  1. 结构化行:collectIndexInjections() 通过一次 webserver/index-inject 事件收集,订阅方各自推入当前行。
  2. 每次都是最新:调用时重新收集,订阅方可以读到当时的模块图与主题偏好。
  3. 原始逃生口:tapIndex(transform) 注册纯 html 到 html 的转换。
  4. 应用顺序:renderIndex(html) 先渲染结构化行,再按注册顺序应用 tap。
  5. 谁调用:fallback 所有者渲染每次 index 响应时调用。
  6. 模块清单:客户端模块包正是以启动 manifest 行回应这个事件。

DSH plugin 的配置与生命周期:监听、压缩与拆卸

一句话结论:激活即监听,失败就拒绝初始化;拆卸必须强制关闭连接。

配置取值默认
host127.0.0.1 或 0.0.0.0回环
port数字,0 表示系统分配—
compressionnone / gzipnone
compressionLevel0–91
compressionThresholdBytes最小压缩长度1024
  1. 绑定即暴露:载体不拥有 TLS、认证或 Origin 策略,绑非回环地址就是把服务暴露出去,你必须自己补上这些控制。
  2. 随附命令更保守:dsh web 选回环并拒绝 --host 0.0.0.0,其 Connection 插件负责 Host/Origin 校验与会话认证。
  3. 压缩只作用于符合条件的 socket 响应:已有内容编码、no-transform、范围响应、SSE、ZIP 与预压缩文件保持 identity。
  4. 监听失败:初始化被拒绝,启动过程报告失败的 fiber。
  5. 异常处理:处理器抛错记警告并回 400(响应头已发出则销毁 socket),不会让进程退出。
  6. 拆卸:close() 配 closeAllConnections(),否则 SSE 一类长连接会让拆卸挂起。

DSH plugin 排查注意事项

一句话结论:HTTP 载体问题先分「路由没命中」「席位被占」「index 没注入」三类。

  1. 请求 404 → 没有命名路由命中且 fallback 未认领,或路径与注册不一致。
  2. 路由冲突报错 → 重复的 (kind, path) 或重复 upgrade 路径,属配置错误。
  3. fallback 注册抛错 → 已有所有者,检查是不是重复认领。
  4. 注入没生效 → 确认 fallback 所有者调用了 renderIndex,且行在事件里推入。
  5. gzip 没压 → 响应属于 identity 白名单(范围、SSE、预压缩等)。
  6. 修复状态如实:本文的匹配顺序、席位唯一性、index 挂接与配置语义均取自官方「HTTP 服务器」页面;静态认领者细节以对应包源码为准。

来源:HTTP 服务器、dsh-host-webserver 源码、dsh-host-frontend-static。

常见问题

DSH plugin 注册的路由是怎么匹配的,注册顺序有影响吗?

DSH plugin 的路由匹配固定为:先查 exact 表,再取最长匹配前缀,最后落到 fallback。注册顺序不携带任何面向请求的语义,具名路由在组合上必须互不相交。

DSH plugin 里,fallback 席位能注册多个处理器吗?

不能,DSH plugin 的 fallback 席位只有一个所有者,第二次注册会抛错,因为两个回退无法组合。发布的 Web 组合由前端静态插件认领该席位。

DSH plugin 里,重复注册同一个路由会发生什么,具体要注意什么?

会抛错,DSH plugin 把重复的 (kind, path) 视为配置错误,因为路由模式是组合层约定。HTTP upgrade 路由同理:同一路径只能有一个协议所有者。

DSH plugin 里,index.html 的注入有哪两种方式?

DSH plugin 提供两条:结构化的 IndexInjection 行,以及原始 html 到 html 的 tapIndex 转换。渲染时先应用结构化行,再按注册顺序应用 tap 转换。

DSH plugin 里,监听端口被占用时会发生什么,具体要注意什么?

DSH plugin 的 WebServer 在激活时立即监听,监听失败(例如端口被占用)会让初始化被拒绝,启动过程会报告失败的 fiber,而不是静默降级。

相关术语

WebRoute(命名路由)
WebRoute 是 DSH plugin HTTP 载体上的一条命名路由,含 exact 或 prefix 的匹配方式、绝对路径与拥有完整响应生命周期的处理器。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web-server
WebRouteKind(路由匹配方式)
WebRouteKind 决定路径如何匹配:exact 逐字匹配路径名,prefix 匹配该前缀及其下任意子路径。匹配顺序永远是 exact、最长 prefix、fallback。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web-server
fallback 席位
fallback 席位是 DSH plugin HTTP 载体上唯一的回退处理器,应答所有未被命名路由匹配的请求。它只有一个所有者,第二次注册抛错。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web-server
IndexInjection
IndexInjection 是 DSH plugin 的结构化 index.html 注入行,通过一次 webserver/index-inject 事件收集,每次调用都是最新状态。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/web-server

来源