Firefox 扩展调用 Ky,构造请求时就报 entries 不可迭代
Ky 2.0.2 在 Firefox 内容脚本中可能于合并 Headers 时抛错,尚未进入 fetch。先隔离 Xray 下的迭代失败,再选择符合原权限边界的请求路径。
同一个浏览器扩展在 Chrome 中正常,放到 Firefox 内容脚本后,Ky 请求却还没出现在 Network 面板就失败:
TypeError: source.entries() is not iterable
如果堆栈停在 mergeHeaders,环境是 Ky 2.0.2、Firefox Developer Edition 153.0b13 的 Manifest V3 内容脚本,应先检查这个执行环境里的 Headers 迭代。此时请求可能尚未进入 fetch,修改服务端跨域响应头不会修好发生在请求构造阶段的 TypeError。
空 headers 也会经过合并
Ky 2.0.2 在构造请求时创建 Headers,并调用 source.entries() 遍历键值对。因此,即使业务没有显式配置 headers,也会经过这条路径。
Firefox 内容脚本通过 Xray 包装访问部分 DOM 对象。字符串命名的方法与依赖 Symbol.iterator 的迭代协议,在这种边界上并不总有相同表现。对应环境中,直接迭代 Headers 的最小对照就可能失败,不需要先引入 Ky:
const headers = new Headers({ Accept: 'application/json' });
for (const entry of headers.entries()) {
console.log(entry);
}
这段对照只使用不含认证信息的固定头。应在同一内容脚本环境判断,不要拿扩展后台、普通网页控制台或 Node 的结果替代;它们不一定经过相同包装。
不能把这一现象写成所有 Firefox 版本、所有扩展上下文都不支持标准迭代,也不能据此判定打包器把 for-of 转坏了。先保留实际版本、执行位置和完整堆栈。
选一条不依赖这段封装的请求路径
请求需求简单时,可以在同一内容脚本里用原生 fetch 隔离客户端封装,明确保留方法、凭据、请求头、状态检查和解析契约。下面只演示读取同站 JSON 状态接口:
const url = new URL('/api/status', location.href);
const response = await fetch(url, {
method: 'GET',
credentials: 'same-origin',
headers: { Accept: 'application/json' },
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
/api/status 必须替换成应用实际允许访问、且确实返回 JSON 的入口。原生 fetch 不会自动复制 Ky 的重试、超时或钩子,这些已有行为要明确保留。它也不会因为写在扩展中就自动取得额外跨域权限;如果后续出现 CORS、权限或认证错误,应按那条新错误继续排查。
不宜仅为绕过迭代失败就把请求移入网页主世界,或开放任意 URL 的后台代理。若原架构已经使用后台消息转发,仍需维持目标白名单、消息校验与凭据边界。
升级和补丁都要核对实际触发点
截至 2026 年 10 月 25 日,正式 Ky 2.2.0 的相关合并代码仍可看到 Headers.entries 路径。不能只因版本更新,就声称这一 Firefox 场景已修复。
项目若维护局部补丁,Headers.forEach 的回调参数是 value、key;不能把原来解构的 key、value 顺序直接搬过去。URLSearchParams 与 FormData 也有其他迭代位置,只改第一个 mergeHeaders,可能只是让异常移动到下一处。补丁应绑定具体依赖版本并经过原扩展上下文回归,不把一次手工修改 node_modules 当成长期修复。
最终检查同一 Firefox 内容脚本里的普通 GET、查询参数、重复查询键和所需请求体。先确认请求能构造并真正发送,再分别核对网络权限、响应和业务结果;Chrome 正常不能替代这一轮验证。


