DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

vi0let-dev /

vi0let-dev/dsh-free-web-search

Verified

DSH plugin that adds third-party free web search to DeepSeek Harness — Bing, Google, Baidu, Yandex, no API key required. Includes proxy support (HTTP/SOCKS5), a latency test that recommends the best backend, and one-click switching between the plugin and official search. Zero dependencies.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@6bbf2350
dsh-free-web-search — Free · Fast · Powerful Web Search

dsh-free-web-search

给 DeepSeek Harness 加一个不需要任何 API key 的 Web 搜索提供方,附带代理支持与延迟测试。

License: MIT Dependencies: 0 Tests: 242 passing

官方搜索走 DeepSeek 的 Anthropic 兼容接口,需要一个 DEEPSEEK_API_KEY(或账号登录态)。这个插件换一条路:向 ctx.web 搜索缝隙注册一个 free-web 提供方,由公开的免费后端来回答搜索。

free-web-search
      │
      ├─ 0. bing        bing.com/search(默认启用:无需配置、无需代理、实测稳定)
      │
      │  以下为可选后端,在设置页勾选后启用:
      ├─ 1. searxng     公开实例的 JSON API(元搜索,一次请求聚合多引擎)
      ├─ 2. google      google.com/search(通用覆盖最好;通常需要代理)
      ├─ 3. baidu       baidu.com/s(中文查询最强;实测可直连)
      ├─ 4. yandex      yandex.com/search(俄语有用;常被验证码拦)
      ├─ 5. duckduckgo  html / lite 结果页(无需配置,抓取型)
      └─ 6. wikipedia   MediaWiki 官方 API(最稳,但只覆盖百科类)

默认只启用 bing。 它是唯一「不需要配置实例、不需要代理」且实测能稳定回答的后端,所以新装即可用,不会把延迟预算花在当前网络里根本答不了的后端上。其余后端都在设置页里,一个勾选框之遥;延迟测试会告诉你哪些在你这儿可达。

按顺序尝试,第一个给出可用结果的胜出。可选项的顺序按可靠性而非结果质量排:能稳定回答的普通引擎,胜过经常失败的高级引擎——因为失败要先用延迟买单才能轮到下一个。

三个特性

1. 多后端(含 Google / 百度 / Yandex)

后端 类型 实测(本机,无代理)
searxng JSON API ❌ 5 个公开实例全超时
google 抓取 ⚠️ 见下(JavaScript 壳页)
bing 抓取 ✅ 10 条 / 546ms
baidu 抓取 ✅ 5 条 / 1077ms(中文结果正确)
yandex 抓取 ⚠️ HTTP 200 但是验证码页
duckduckgo 抓取 ❌ 两端点全超时
wikipedia JSON API ❌ 超时

Baidu 的解析基于实测而非猜测。 抓下真实结果页(1.2MB)后发现:结果容器带 mu="真实URL" 属性,所以不需要跟随跳转就能拿到目标地址。这很关键——另一种做法(逐个解析 baidu.com/link?url= 跳转)会把请求数乘以结果条数。

同时实测到 c-container 这个类名在页面里出现 105 次,大部分在嵌入的 CSS 和一个反馈表单里,所以解析器要求容器必须带 mu= 属性,而不是只匹配类名。

Yandex 的结果解析器未经验证(抓取时只拿到验证码页,没有结果标记可对照)。这一点在 src/backends/yandex.js 里明确写了。已验证的是验证码路径——这反而更重要,因为它让"被拦"被如实报告,而不是误报成"页面改版"。

Google 的实测结论(重要)

配上可用代理后重测(代理 CONNECT 6ms 成功),Google 仍然拿不到结果,但原因不是网络也不是解析器:

status: 200   最终 URL 正确   93,468 字节
<h3> 数量: 0      class="g" 数量: 0      <div> 数量: 2
<noscript> 重定向到 /httpservice/retry/enablejs

Google 对这个客户端返回的是「需要 JavaScript」的空壳页,结果由脚本异步拉取,HTML 里根本没有任何结果可解析。

而且这不是某个参数的问题——实测以下全部变体都返回同一个 93KB 空壳:默认请求、gbv=1、udm=14、gbv=1&udm=14、nojs=1、complete=0、lite=1、Android 客户端串、source=hp、以及纯 HTTP。没有可回退的服务端渲染版本。

所以插件把它识别为独立的一种结果,报错明确说:

Google served a JavaScript-only page with no results in the HTML (the /httpservice/retry/enablejs shell).

而不是含糊地报 layout may have changed——后者会让人去改解析器,而问题不在解析器。这条诊断是实测驱动的,isGoogleJavaScriptShell() 有专门的测试和夹具。

实际含义:Google 后端的可用性取决于出口 IP 与客户端指纹,配代理可能有帮助(改变被分类的方式),但不保证。要可靠就用 SearxNG 实例(由实例去面对 Google),或者接受用 Bing / 百度。

2. 代理(默认空 = 直连)

undici 在 DSH 宿主运行时无法导入(ERR_MODULE_NOT_FOUND,已实测),所以 fetch + ProxyAgent 这条路走不通。Node 的实验性 NODE_USE_ENV_PROXY 也不能用:它在进程启动时读取一次,而这是个可能后来才拿到代理的长驻进程。

所以隧道是手写的(node:net / node:tls / node:http),依赖数仍然为 0:

  • HTTP / HTTPS 代理 — 走 CONNECT(Squid、mitmproxy、Charles、Fiddler、Clash HTTP 模式、企业代理)
  • SOCKS5 / SOCKS5H — 走 SOCKS5 CONNECT(Clash、V2Ray、Shadowsocks 常只开 SOCKS 端口)
  • 认证 — 两者都支持 user:pass@(HTTP Basic / SOCKS5 用户名密码子协商)
  • 不支持的:SOCKS4(无法远程解析域名,已被 socks5h 取代)、PAC 文件、代理客户端证书

配置:全局代理 + 可按后端覆盖

- id: free-web-search
  name: 'dsh-free-web-search'
  config:
    proxy: 'http://127.0.0.1:7890'          # 全局默认,留空即直连
    proxyByBackend:
      baidu: 'direct'                        # 百度直连更快,不绕代理
      google: 'socks5://127.0.0.1:1080'      # 谷歌走 SOCKS5
    noProxy: ['internal.corp']               # 这些域名始终直连

也支持环境变量,且已有的 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY 会被自动识别(useEnvProxy: false 可关闭)。

3. 延迟测试(只给建议,不改配置)

点击「开始测速」后,插件逐个连接每个已启用后端的服务器,测量分段耗时:

阶段 含义
连接 TCP 连接,或经代理的隧道建立(HTTP CONNECT / SOCKS5)
TLS TLS 握手
总延迟 上述之和,加上首字节时间

它不发任何搜索请求,也不使用查询词——探测的是各服务的首页(HEAD /)。这里要回答的是「从这台机器访问这个服务有多快」,而不是「能搜到什么」。用 HEAD 而不是 GET,是因为首页动辄几百 KB,为了测延迟把七个页面都拉下来既慢又不礼貌;服务器回 405 也算可达。

排序仅按总延迟,未响应的后端排最后。插件只给建议 + 可复制的配置片段,决定权在你。

⚠️ 可达 ≠ 可用,这一点界面上也会明说。实测中:Google 返回不含结果的 JavaScript 空壳页、Yandex 返回验证码、公开 SearxNG 实例可能关闭了 JSON 输出——它们都会被测成「可达」。所以只按延迟排序,可能把一个快但搜不到东西的后端排到前面。这也是插件不自动应用建议的原因。

设置页 UI

在 DSH 设置页新增「免费搜索」面板,四个分区:

  1. 默认搜索服务 —— 两个按钮:设为本插件搜索 / 恢复 DeepSeek 官方。这一项决定 web_search 到底用谁,原因见上一节。
  2. 代理 —— 输入框填 host:port,可保存 / 测试 / 改为直连。
  3. 搜索后端 —— 勾选启用的后端,用箭头调序;显示人类可读名称。默认只勾 bing。
  4. 延迟测试 —— 点击按钮探测,出排名表 + 建议 + 「采用此顺序」。

侧栏图标:外壳给每个设置分区画同一个齿轮,本插件那一项因此和「通用设置」长得一样。外壳没有提供设定图标的接口,所以插件把自己的导航按钮打上标记,用 CSS 隐藏齿轮、以 mask 画一个放大镜代替。图形用 currentColor 取色,明暗主题与选中态都自动适配;定位靠匹配分区名称,所以不会误伤弹窗自己的「设置」按钮。

「单独测试代理」是独立功能,因为「搜索失败」有两种原因、修法完全不同:代理不通(改代理)vs 代理正常但引擎拦截(改代理没用)。混在一起报会让人去修错的东西。

修改写到哪里

不写 cordis.patch.yml。 那是 loader 的文件,还存着你其它插件条目,第三方插件去改写它既意外又容易写坏 profile。所以改动写入插件自己的文件:

$DSH_HOME/dsh-free-web-search/settings.json

优先级(低 → 高):

内置默认值  <  环境变量  <  cordis.patch.yml  <  settings.json

设置文件优先,因为它是你在界面上的最近一次明确操作。这是实现细节,界面不展示——你在设置页看到的只有代理输入框和后端勾选框;文件路径、覆盖状态、清除按钮都已移除,避免把内部机制摊在用户面前。想回到配置文件的值,直接删除该文件即可。

安装

方式一:从 GitHub 直接安装(推荐)

本插件是纯 JavaScript、零依赖、无需构建,所以可以直接从 Git 仓库安装——不必等发布 npm 包。

在 DSH 界面里:

设置 → 插件 → 添加插件

输入:

github:vi0let-dev/dsh-free-web-search

装完重启 DSH。

或者手动改配置(效果相同):

cd $env:DSH_PROFILE_DIR
pnpm add github:vi0let-dev/dsh-free-web-search

然后把 dsh-free-web-search 加进该目录 package.json 的 dsh.profile.bundles 数组,再重启 DSH。

方式二:本地路径安装(开发用)

cd $env:DSH_PROFILE_DIR
# package.json 的 dependencies 加一行:
#   "dsh-free-web-search": "file:<插件所在路径>"
# dsh.profile.bundles 加一行:
#   "dsh-free-web-search"
pnpm install
# 重启 DSH

⚠️ file: 依赖在 pnpm 里是复制而非软链。改完源码要重新 pnpm install(或手动复制到 node_modules)才会生效。

装完必做一步:切换默认搜索服务

重启后进 设置 → 免费搜索 → 默认搜索服务,点「设为本插件搜索」。

这一步不能省。DeepSeek 官方的搜索提供方即使没有 API key 也会自称「可用」(它的 available() 里有两个恒为真的判断),所以缝隙永远优先选它、然后以 no API key 失败——本插件作为「兜底」永远轮不到。原因详见 与已装插件共存。

切换立即生效,不需要再次重启。想换回去,点同一处的「恢复 DeepSeek 官方」。

配置项

配置项 默认 说明
backends ['bing'] 启用的后端与顺序。未知名字丢弃并告警;你给的顺序会被保留,不再重排。
proxy ''(直连) 全局代理:http:// https:// socks5:// socks5h://
proxyByBackend {} 按后端覆盖;direct/none/off = 该后端直连
noProxy [] 始终直连的域名(父域名匹配)
useEnvProxy true 是否读取 HTTPS_PROXY 等环境变量
searxngInstances 5 个公开实例 建议换成自己搭的
timeoutMs 12000 单请求超时(上限 60000)
totalTimeoutMs timeoutMs × 2 整条链总预算(上限 120000)
maxResults 5 结果条数(上限 20)
wikipediaLang en 中文用 zh
takeover false true = 无条件抢占搜索槽位
digest false true = 额外把结果渲染成纯文本放进 content

环境变量前缀 DSH_FREE_WEB_SEARCH_:BACKENDS TIMEOUT_MS TOTAL_TIMEOUT_MS SEARXNG_INSTANCES WIKIPEDIA_LANG MAX_RESULTS TAKEOVER DIGEST PROXY NO_PROXY PROXY_BY_BACKEND(形如 google=http://a:1,baidu=direct)USE_ENV_PROXY。

预算为什么是「预留式分配」

只设单请求超时不够:链上每多一个后端,最坏情况就多一份超时时间,几个后端就能把一次搜索拖到一分多钟。

但单纯共享一个 deadline 也不够——这是实测出来的:4 个后端、24s 预算时,5 个卡住的 SearxNG 实例把预算全吃光,后面三个后端全部报 skipped,根本没被尝试。这恰恰是最糟的失效模式,因为「第一个挂了、后面某个本来能work」正是这条链存在的唯一理由。

所以预算是预留式:每个后端只拿「剩余 − 给后面每个预留的一份」;快速失败把时间还回池子;预算小到无法预留时改为平均分配(短尝试还可能成功,不尝试必然失败)。

测试

node test/smoke.mjs              # 离线单元测试,187 项,无需网络
node test/proxy-e2e.mjs          # 代理端到端,13 项,起真实本地代理
node test/client-render.mjs      # 设置页渲染与交互,26 项,无需浏览器
node test/extract-real-seam.mjs  # 从你的 app.asar 抽出真实 ctx.web
node test/real-seam.mjs          # 对真实缝隙的集成测试,16 项
node test/live.mjs               # 联网体检(只报告不判定)
node test/live-new-backends.mjs  # 新后端 + 延迟测试的联网体检
node test/live-proxy.mjs 127.0.0.1:7890   # 带代理的联网体检

合计 242 项。

实测:本地 HTTP/SOCKS5 混合端口代理(127.0.0.1:<port>)

用真实代理跑过一轮,结论如下。

写法:127.0.0.1:<port> 直接可用——不带 scheme 会被按 HTTP 代理处理。Clash Verge 等混合端口同时支持 HTTP CONNECT 和 SOCKS5,所以下面四种写法都能用:

写法 解析结果
127.0.0.1:<port> http://127.0.0.1:<port>
http://127.0.0.1:<port> http://127.0.0.1:<port>
socks5://127.0.0.1:<port> socks5://127.0.0.1:<port>
socks5h://127.0.0.1:<port> socks5h://127.0.0.1:<port>

代理确实生效:实测出口 IP 在直连与走节点时不同(具体地址不外记录,见下)。

隐私说明:本文档早期版本写入了实测时的真实出口 IP 与代理节点 IP,以及本机用户名与工作区绝对路径。这些已在审计中移除——它们属于个人网络拓扑信息,对读者也毫无价值:你只需知道「直连与走代理的出口 IP 不同」即可判断代理是否生效,具体地址请用 node test/live-proxy.mjs <你的代理> 自己测。

通过代理后的可用性(实测,非推断):

后端 直连 走代理
bing ✅ ✅ 3/3,约 700ms
baidu ✅ ✅(偶尔被拦)
duckduckgo ❌ 超时 ✅ 3/3,约 1100ms,10 条
wikipedia ❌ 超时 ✅ 3/3,约 1750ms,5 条
google ❌ 超时 ⚠️ HTTP 200 但是 JS 空壳页(见上)
searxng ❌ 超时 ⚠️ 能连上实例,但实例本身拒绝(JSON 关闭 / 403 / 429)
yandex ⚠️ 验证码 ⚠️ 仍是验证码

结论:代理是有用的——它把 DuckDuckGo 和 Wikipedia 从完全不可用变成了可用。

这一轮实测抓出一个真 bug(已修):searxng / bing / duckduckgo / wikipedia 这四个原有后端没有把 proxy 传给 HTTP 层。我给新增的 google/baidu/yandex 加了代理支持,却漏了这四个,于是它们悄悄走直连,在任何"被墙"的网络里必然超时。

这个 bug 特别隐蔽:桩掉 transport 的单元测试发现不了——桩无论走不走代理都会回答。是拿真实代理跑才暴露的(wikipedia 走 requestText 6/6 成功、走 backend 0/6 失败,同一秒内交替测试)。现在 smoke.mjs 里有一条专门的回归测试,断言每个后端都把 proxy 传下去,并且我做了变异验证:把 bug 塞回去,测试确实会失败。

代理为什么要有端到端测试

解析一个代理 URL 正确,完全不能证明请求能穿过它。 手写的 CONNECT/SOCKS5 实现要在握手字节、认证子协商、TLS 分层上全部正确,而这些失败在桩掉 socket 的单元测试里根本不会出现。

所以 proxy-e2e.mjs 在回环上起真实的 HTTP CONNECT 代理和 SOCKS5 代理(都带认证),用运行时的 node:crypto 手搓一张自签证书起真实 HTTPS 源站,然后让插件的 HTTP 层真的穿过去。它覆盖:CONNECT 隧道、SOCKS5 隧道、Basic 认证、SOCKS5 用户名密码、407 / 凭据被拒 / 代理要求认证但没配、域名以 0x03 地址类型发送(证明是让代理解析而非本地解析)。

这套测试当场抓出两个真 bug:插件把 rejectUnauthorized 硬编码成 true(会静默破坏私有 CA 和企业拦截代理),以及测试自身泄漏 tunnel socket 导致 server.close() 永久挂起(现在有 90 秒看门狗把挂起变成可见失败)。

设置页为什么要渲染测试

能通过语法检查的 bundle,不等于能用的 bundle。 真正的失效模式是:字典缺一个键、某个 prop 是 undefined、嵌套组件在定义前被引用——这些都会让设置页渲染成一片空白,而 node --check 全都看不出来。

client-render.mjs 用 test/react-shim.mjs 真正渲染整棵组件树,并用 stub 的 fetch 走完「加载配置 → 显示」这条异步路径,断言代理、后端顺序、按钮、以及 host 报错都被渲染出来。它还校验 zh/en 两份字典的键完全一致——缺键正是最典型的空白页成因。

React 不在工作区也不在 DSH 运行时里(由外壳在浏览器提供),所以 shim 是必需的。诚实地说:渲染测试通过只说明面板逻辑没问题,不代表 markup 完美——它不会发现非法的 DOM 属性或无障碍问题。这一点写在 shim 的文件注释里。

缝隙集成测试

ctx.web 的选人算法不属于本插件,用自己写的替身去测「我不会造成冲突」只能证明替身同意我的看法。所以 real-seam.mjs 直接从你本机的 app.asar 抽出 @deepseek-ai/dsh-web 的真实实现来驱动,验证官方提供方在场时搜索仍然成功(无 WEB_PROVIDER_AMBIGUOUS)。

抽出的缝隙源码是 DeepSeek Harness 的,不是本插件的,所以不入库——由 extract-real-seam.mjs 按需读取,已加进 .gitignore。

隐私与安全审计(可以放心)

本插件曾经完整读过一遍自己的全部源码(index.js、client.js、src/ 下所有模块),只为一个目的:查清它到底会把什么东西发到哪里、把什么东西写到磁盘上。结论如下,不夸大、也不回避——有一处 debug 日志会带查询词,单列了出来。

关注点 结论
遥测 / 统计 / 回传 ✅ 无。没有埋点、没有统计、没有「错误上报」
外发网络去向 ✅ 只有两类:发给搜索引擎的搜索请求、发给同一批引擎的 HEAD / 延迟探测
搜索内容留存 ✅ 不落盘。查询词与结果只存在于当次请求的内存里
磁盘写入 ✅ 只有一个自有文件,原子写入
代理密码 ✅ 离开主机前已脱敏
设置页 API ✅ 三道闸(回环 / 防 DNS rebinding / 防跨站)
日志 ⚠️ 仅 debug 级会带查询词,默认关闭、不外发
仓库与文档 ✅ 已脱敏(真实 IP、用户名、本机路径已移除)

1. 没有遥测,也没有「回传」

全仓库搜 fetch、sendBeacon、WebSocket、analytics、telemetry 等,唯一的浏览器侧网络调用是设置页面板 fetch 本插件自己的设置 API(/api/dsh-free-web-search/*),唯一的宿主侧网络调用在 src/http.js 与 src/latency.js 里——目标全部是七个搜索引擎的域名。没有任何第三方收集端点,也没有把错误、查询词或结果发往任何别处。它不收集你搜了什么,因为它自己也不知道你搜了什么:搜索请求由宿主进程直接发到引擎,结果直接还给调用方,中间没有落到任何存储。

2. 磁盘上只有一个文件

设置改动写入插件自己拥有的文件:

$DSH_HOME/dsh-free-web-search/settings.json

而且采用原子写入(先写临时文件再 rename),中途崩溃不会留下半截文件。它从不改写 cordis.patch.yml 或其它插件的文件——那属于 DSH loader,写坏会连累整个 profile。这个文件里只有你自己的配置(代理地址、后端勾选与顺序等),不含搜索历史、不含搜索结果。想彻底清空,删掉该文件即可。

3. 代理密码在离开主机前就被遮住

代理 URL 里若带 user:pass@,src/routes.js 的 redactProxy() 会把密码替换成 ******** 后再返回给界面渲染。真实值只保留在宿主侧,用于编辑框回填(否则一次保存就会把密码覆盖成星号)。这个值之所以敢发回浏览器,是因为设置 API 只监听回环地址、且被下面三道闸挡住跨站读取——这是一次有意的取舍,源码注释里写明了,不是疏漏。

4. 设置页 API 的三道闸

设置页的宿主侧路由能读配置、能替用户发起探测,所以不能被人跨站触发。三道防护(与本 profile 里另一个已装插件一致,因为它们防的是不同攻击):

  1. 只接受回环连接——req.socket.remoteAddress 必须是 127.0.0.1 / ::1 等;
  2. Host 必须是回环字面量——防 DNS rebinding(把 evil.example 指到 127.0.0.1 让请求变成同源);
  3. 要求自定义请求头——强制浏览器先发 preflight,而本服务从不回应 preflight,跨站 POST 根本发不出去。

5. 一处如实说明:debug 日志会带查询词

src/provider.js 里有一条 debug 级别的日志,形如 "...served by bing (10 sources)",其中包含当次查询词。说明三点:

  • 它是 debug 级,生产环境默认不输出;
  • 它写进的是 DSH 宿主自己的日志器(logger.debug),不是 console,也不会被本插件外发到任何地方;
  • 关闭 debug 日志后,这条就完全不存在。

所以「日志里会不会出现我搜了什么」的答案是:只有当你主动开启 debug 日志时才可能,且只在本机,插件不会把它送出去。

6. 仓库与文档本身也脱敏过

早期文档在「实测代理」一节写过真实的出口 IP、代理节点 IP、本机用户名与绝对路径。这些属于个人网络拓扑信息,对读者毫无价值,已在审计中移除(具体见下方「实测:本地 HTTP/SOCKS5 混合端口代理」一节末尾的隐私说明)。测试夹具全部是合成样本,不含任何真实抓取页面的内容。

一句话总结:这个插件把查询词只发给你要用的搜索引擎(这是搜索的固有代价,可配代理改变出口)、把配置只写进自己一个文件、把代理密码在主机边界遮住,不做任何遥测、不回传、不留存。不放心的话,源码全在上面,src/ 每个文件都能直接读,零依赖也意味着没有隐藏的第三方包可藏东西。

与已装插件共存,以及为什么必须手动切换

ctx.web 的选择逻辑与注册顺序无关,且拒绝猜:没配置 id 且有多个可用提供方时抛 WEB_PROVIDER_AMBIGUOUS。

本插件注册为兜底:只在显式选中、或没有别的可用搜索提供方时接管。

id 归属
deepseek-official DSH 自带搜索
http DSH 自带抓取
free-web 本插件 ✅

已核验:本 profile 里已装的两个第三方插件(dsh-session-trash、dsh-our-free-model)都不碰 ctx.web。依赖数为 0。

但兜底不会自动生效(重要)

最初的设想是:官方提供方没有 API key 时会报告自己不可用,于是兜底自动接管。这个假设是错的,实测从 app.asar 里读到的官方实现是:

available() {
  return ((options.apiKey?.length ?? 0) > 0
       || options.resolveApiKey !== void 0        // 插件总是传函数 → 恒为真
       || options.resolveAccountToken !== void 0  // 同理 → 恒为真
  ) && URL.canParse(...) && ...
}

那两个 !== void 0 恒为真(插件总会传入 resolver 函数),所以官方提供方即使没有 key 也永远自称「可用」,只在真正搜索时才抛 WEB_PROVIDER_CREDENTIAL_MISSING。

后果:在一台没有 DeepSeek 凭据的机器上,装了这个能用的免密钥搜索插件,搜索仍然是坏的 —— 因为缝隙永远选官方,官方永远失败。

所以设置页第一项是 「默认搜索服务」,两个按钮:

  • 设为本插件搜索 —— 让缝隙改用本插件
  • 恢复 DeepSeek 官方 —— 交还控制权

切换是立即生效的:缝隙在每次搜索时读取 searchProviderId,不需要重启。

「恢复官方」的实现是清除该 id,而不是写入字面量 deepseek-official。后者在不曾注册官方提供方的组合里会让每次搜索都抛 WEB_PROVIDER_CONFIGURED_MISSING。清除则让缝隙回到自己的选择逻辑——并且如果此时只有本插件注册,缝隙会退回「恰好一个可用提供方」规则继续用本插件,搜索不中断(这一点是在真实缝隙上验证过的,所以那个按钮不会被禁用)。

设置页路由有三道闸(回环、Host 字面量防 DNS rebinding、自定义头防跨站)。

已知限制(说实话)

1. 本机网络是选择性可达的。 实测:bing ✅、baidu ✅、google ❌(无代理超时)、yandex ⚠️ 验证码、searxng/ddg/wikipedia ❌ 超时。所以是这些域名的 DNS 或出网被拦,不是整机断网。(这修正了我早先"整机没网"的错误判断——当时只有三个后端全部失败这一个样本。)

2. Google 返回 JavaScript 空壳页,配代理也不一定能用。 见上方「Google 的实测结论」。代理已实测可用(CONNECT 6ms),Google 仍返回无结果的空壳。要可靠请用 SearxNG。

3. Yandex 结果解析器未经验证(见上)。它默认启用但排在较后;若确认不可用,用 backends 去掉即可。

4. 抓取型后端会因改版失效。 google / bing / baidu / yandex / duckduckgo 都是解析结果页。失效时报 layout may have changed——这条错误就是需要改代码的信号。搜索引擎改版是常态,这是抓取路线的固有代价。

5. 默认公开 SearxNG 实例不保证可用。 志愿者在跑,随时可能限流或下线。要稳定就自己搭一个。

6. 后端顺序尝试,没有并发。 并发更快,但会让"哪个后端答的"不确定,也会在第一个成功时浪费已发出的请求。用可预测性换确定性。

7. 延迟测试结果只代表当下,且只反映可达性。 延迟随网络状况和公开实例负载变化;更重要的是它不检验能否搜到结果(见上方「可达 ≠ 可用」),所以采纳建议前建议重跑,并结合实际搜索结果判断。

8. 代理不支持的形态:SOCKS4(无法远程解析域名)、PAC 文件、代理客户端证书。HTTP/HTTPS/SOCKS5/SOCKS5H 都支持。

结构

dsh-free-web-search/
├── index.js                     插件入口:注册提供方 + 挂载设置页 API
├── client.js                    浏览器半身:设置页面板(代理 / 后端选择 / 延迟测试)
├── cordis.patch.yml             bundle patch:一行 insert
├── package.json
├── src/
│   ├── provider.js              提供方实现 + 兜底/接管 + 预算预留分配
│   ├── config.js                配置归一化(手写,无 schema 库)
│   ├── http.js                  统一 HTTP 层:node:http 实现,支持代理与手写重定向
│   ├── proxy.js                 代理:CONNECT 隧道 + SOCKS5 握手 + 策略解析
│   ├── proxycheck.js            代理连通性探测与失败归因
│   ├── routes.js                设置页 API(三道安全闸 + 密码脱敏)
│   ├── latency.js               延迟测试:连接/TLS/首字节,只建议不改配置
│   ├── settings.js              运行时设置读写(不碰 cordis.patch.yml)
│   ├── provider-control.js      切换 web_search 用哪个提供方(立即生效)
│   ├── html.js                  零依赖 HTML 工具
│   ├── urls.js                  共享 URL 校验 + base64url 解码
│   └── backends/
│       ├── index.js             后端契约与默认顺序
│       ├── searxng.js           JSON API,多实例回退
│       ├── google.js            google.com/search + /url?q= 解包
│       ├── bing.js              bing.com/search + ck/a 解包
│       ├── baidu.js             baidu.com/s + mu= 真实地址
│       ├── yandex.js            yandex.com/search + 验证码识别
│       ├── duckduckgo.js        html + lite 双端点
│       └── wikipedia.js         MediaWiki API
├── docs/
│   └── banner.webp              README 顶部横幅(PNG 母版不入库,见 .gitignore)
└── test/                        共 242 项
    ├── smoke.mjs                离线单元测试(187 项)
    ├── fixtures.js              测试夹具(合成样本,非真实抓取页面)
    ├── proxy-e2e.mjs            代理端到端(13 项,真实本地代理 + 自签 HTTPS 源站)
    ├── client-render.mjs        设置页渲染与交互(26 项)
    ├── react-shim.mjs           极简 React 兼容层(仅供渲染测试)
    ├── real-seam.mjs            对真实 ctx.web 的集成测试(16 项)
    ├── extract-real-seam.mjs    从 app.asar 抽出真实缝隙
    ├── live.mjs                 联网体检
    ├── live-new-backends.mjs    新后端 + 延迟测试的联网体检
    ├── tls-origin.mjs           测试用的本地自签 HTTPS 源站
    └── live-proxy.mjs           带代理的联网体检

许可

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 6bbf2350bd24

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout