HeaderEditor 修改响应体(Modify Response Body)实战指南:编码、拦截阶段与自定义函数的原理详解
开发工具网络【免费下载链接】HeaderEditorManage browsers requests, include modify the request headers, response headers, response body, redirect requests, cancel requests项目地址https://gitcode.com/gh_mirrors/he/HeaderEditor点击查看免费下载本文基于 HeaderEditor 仓库中的官方文档 modify-body.md 与对应源码实现系统讲解修改响应体modifyReceiveBody这一核心功能如何在 Chrome 与 Firefox 下配置响应体替换规则encoding、body.stage、自定义函数三大配置项的实际行为以及底层分别基于 CDPFetch拦截与filterResponseData流过滤的实现机制。读完本文你可以正确配置响应体改写规则包括非 UTF-8 页面、理解 Chrome 调试横幅的来源并掌握自定义函数中val/detail参数的结构差异。功能概览与使用须知HeaderEditor 的修改响应体功能允许你拦截 HTTP 请求的响应并替换其响应体Body内容典型场景是替换页面中的文案、改写返回的 JS 脚本、修改接口返回的 JSON 文本等。使用前需要注意文档明确列出的影响性能与资源占用由于需要读取并重新编码响应内容访问速度与资源消耗会受到一定影响内容下载部分内容下载如经过该链路代理的二进制资源可能受到影响。Chrome 下会出现正在调试此浏览器横幅在 Chrome 上启用该功能后浏览器地址栏下方会出现Header Editor started debugging this browser的提示。这是因为该功能在 Chrome 侧基于chrome.debuggerAPIDevTools Protocol实现扩展一旦attach到标签页浏览器就会展示调试横幅。从源码 chrome-response-modifier.ts 可以看到扩展对每个标签页调用debuggerAPI.attach({ tabId }, 1.3)这正是横幅出现的直接原因。如果不想看到该提示文档给出了两种做法在 Options选项页中关闭 Modify Response Body 开关对应偏好项modify-body以--silent-debugger-extension-api参数启动 Chrome即可隐藏该横幅。功能开关与自动启用modify-body偏好的默认值为false定义在 constant.ts。但有一个便利设计当你在规则编辑器中保存一条modifyReceiveBody规则时扩展会自动把modify-body置为true并弹出已自动开启修改响应体如不需要请手动关闭的提示。相关逻辑位于 edit/index.tsx提示文案对应国际化 keyauto_enable_modify_body见 messages.json。在选项页中该开关的定义见 base-prefs.tsxmodify-body: { langKey: modify_body, type: switch, disabled: IS_FIREFOX !IS_SUPPORT_STREAM_FILTER, },即 Firefox 下如果当前构建不支持filterResponseData流过滤开关会被禁用——这决定了该功能在 Firefox 侧的可用性前提。规则配置界面modifyReceiveBody类型规则的执行配置项由 execution.tsx 渲染与文档Configuration一节的三个小节一一对应Encoding编码下拉框支持过滤搜索选项来自 encoding.ts 维护的 42 种编码列表Request Stage拦截阶段Request/Response二选一仅在非 Firefox环境下显示ruleType MODIFY_RECV_BODY !IS_FIREFOX执行方式普通模式直接填写替换用的响应内容body.value或自定义函数模式isFunction: true代码编辑器中编写val/detail逻辑此外还有一个文档未展开、但源码中明确支持的配置点修改响应体规则可以携带响应头修改Modify body can also modify headers见 execution.tsx。在 Firefox 侧 web-request-handler.ts 会把 body 规则的 headers 一并应用Chrome 侧则在Fetch.fulfillRequest前合并进responseHeaders见 chrome-response-modifier.ts。这一点在 Request 阶段拦截时尤其有用——因为拿不到服务端响应头你可能需要手动补上Content-Type等头。配置项一Encoding编码行为约定文档对该项的约定如下HeaderEditor 默认使用UTF-8解码传输内容。若目标网站不是 UTF-8 编码需要手动指定编码该编码仅用于解码入站内容。修改后的响应始终按 UTF-8 重新编码输出如果不确定页面编码可打开控制台F12→ Network 面板 → 刷新页面查看 Response Headers 中Content-Type里的charset。可用编码列表规则编辑表单提供的编码清单完整收录在 encoding.ts共 42 项涵盖中文utf-8、gbk、gb18030、big5、hz-gb-2312日文euc-jp、iso-2022-jp、shift-jis韩文euc-kr、iso-2022-krWindows 系windows-874、windows-1250~windows-1258ISO 8859 系列iso-8859-2~iso-8859-16不含iso-8859-1/9其他koi8-r、koi8-u、macintosh、x-mac-cyrillic、utf-16be、utf-16le、x-user-defined、replacement。该列表与浏览器 Encoding API 支持的编码集合一致编码全集可查阅 MDN 的 Encoding API 文档。源码中的解码实现解码与编码的核心工具集中在 text-coder.tstextDecode(encoding, buffer)基于 Web 标准TextDecoder并对每种编码缓存 Decoder 实例textDecoder: Mapstring, TextDecoder解码失败时记录错误并返回undefined而非抛错防止单条规则失败拖垮整个响应链路见 text-coder.tstextEncode(text)TextEncoder封装输出恒为 UTF-8对应文档修改后响应总是 UTF-8 编码的约定safeBtoa/safeAtob/uint8ArrayToBase64为 Chrome 的 CDP 通道Fetch.getResponseBody返回 base64、Fetch.fulfillRequest接收 base64提供编解码并做了性能优化——纯 ASCII 内容走快路径直接btoa/atob含高字节时才分块4096转换safeAtob只对utf-8、latin1、windows-1252等ASCII 段与 Unicode 一一对应的编码启用快路径shift-jis、iso-2022-jp等编码不会误走快路径见 text-coder.ts。Firefox 侧调用方式web-request-handler.ts 中textDecode(encoding, buffers)encoding取规则值、缺省utf-8Chrome 侧则是safeAtob(rule.encoding || utf-8, resp.body)见 chrome-response-modifier.ts。配置项二Request Stage拦截阶段文档指出在 Chrome 上你可以选择在请求的哪个阶段拦截阶段行为可访问信息性能Request请求根本不会真正发送到服务器由扩展直接伪造fulfill响应无法访问服务端响应头与响应体多数情况下需要手动配置Content-Type更好无需等待服务器往返Response等待服务器真实响应后再改写自定义函数中可以读取服务端响应头与响应体需等待完整响应而Firefox 上该配置不存在始终为 Response 阶段响应流到达后再经filterResponseData改写。源码中的阶段逻辑UI 层的阶段下拉框仅在非 Firefox 下渲染execution.tsx存储字段为body.stage类型定义在 types.tsstage?: Request | Response。Chrome 侧的阶段生效逻辑见 chrome-response-modifier.ts 的checkStageconst hasResponse this.rules.some(r r.body?.stage Response); const newStage hasResponse ? Response : Request; if (newStage ! this.stage) { this.stage newStage; // 对已附加的标签页重新 disable/enable Fetch }即只要启用规则中存在任意一条stage: Response整个扩展就运行在 Response 阶段否则运行在 Request 阶段阶段变化会触发对所有已 attach 标签页的Fetch.disableFetch.enable重建。Fetch.enable的完整参数见 chrome-response-modifier.tsawait debuggerAPI.sendCommand({ tabId }, Fetch.enable, { patterns: [ { urlPattern: http://*, requestStage: this.stage }, { urlPattern: https://*, requestStage: this.stage }, ], });这里requestStage直接透传为 CDPFetch.enable的合法取值Request/Response与文档描述完全对应。配置项三Custom Function自定义函数函数签名与返回值文档约定自定义函数接收两个参数——val为已按encoding解码后的响应文本detail为当前请求的 detail 对象函数返回修改后的文本。例如把页面上所有 baidu 替换为 Googlereturn val.replace(/baidu/g, Google);从源码结构看实际调用为rule._func(finalBody, detailObj, util)见 chrome-response-modifier.ts 与 web-request-handler.ts第三个入参util是扩展注入的内置工具对象定义在 function-util.ts包含util._lodash 常用函数子集clone、first、uniq、pick、get/set等util.atob/util.btoa带编码感知的安全 base64 编解码safeAtob/safeBtoautil.textDecode/util.textEncode、util.uint8ArrayToBase64。返回值方面文档只提到返回修改后的文本而源码进一步确认还支持返回Uint8Array二进制if (typeof result string result ! finalBody) { finalBody result; hasChanged true; } if (typeof result object result instanceof Uint8Array) { finalBody result; hasChanged true; }见 web-request-handler.ts这意味着自定义函数可以输出非文本内容如图片、zip 片段扩展会按二进制直接写回响应流。detail 对象Firefox 与 Chrome 的差异文档强调detail.browser可取得浏览器类型chrome或firefox两个浏览器的 detail 结构不同Firefoxdetail 与其他自定义函数见 custom-function 文档一致。从 web-request-handler.ts 的CustomFunctionDetail接口可看到其字段idrequestId、url、tab、method、frame、parentFrame、proxy、type资源类型、time、originUrl、documentUrl、incognito、cookieStoreId、requestHeaders、responseHeaders、statusCode、statusLine、browser以及响应体修改专属的rawResponse完整响应的Uint8Array原始字节见 web-request-handler.ts。Chromedetail 的格式是 CDPFetch.requestPaused事件的params对象含requestId、request、responseHeaders、resourceType等可查阅 CDP Fetch 域文档并额外附加了rawResponseFetch.getResponseBody返回的 body 字符串仅当存在函数型规则时才拉取与browser: chrome构造代码见 chrome-response-modifier.tsconst detailObj { ...params, // Fetch.requestPaused 事件参数 rawResponse: resp?.body, browser: chrome, };因此跨浏览器编写函数时建议只依赖detail.browser、detail.rawResponse这类两端共有语义的字段其余字段按浏览器分支处理。一条经过 e2e 测试验证的函数示例仓库的端到端测试 response.spec.mjs 中有一条真实的自定义函数用例拦截mock-js.php的响应用正则把单引号包裹的内容改为双引号包裹并拼接前后缀code: return val.replace(/(.*?)/, ${key1}$1${key1}$1);,测试随后断言页面中脚本实际执行到的值等于改写后的${key1}${key2}${key1}${key2}验证了函数返回值确实成为最终响应体这条链路。实现机制剖析ChromeCDP Fetch 域拦截ChromeResponseModifierchrome-response-modifier.ts完整流程如下规则加载与开关判断initRules从规则表加载启用且type MODIFY_RECV_BODY的规则最终启用条件为rules.length 0 modifyBody !disableAllcheckEnable与选项页modify-body开关、disable-all总开关联动按标签页附加调试器监听tabs.onCreated/tabs.onUpdated触发enableFetch(tabId)先chrome.debugger.attach协议版本1.3再Fetch.enable标签页关闭或debugger.onDetach时清理状态拦截处理Fetch.requestPaused事件回调中先用规则匹配器filter(this.rules, { url, method, responseHeaders, resourceType })过滤resourceType通过resourceTypeMapDocument→main_frame、XHR/Fetch→xmlhttprequest等映射到声明式请求的资源类型命名无命中规则时直接Fetch.continueRequest放行拉取响应体仅当命中规则中存在函数型规则时才调用Fetch.getResponseBodyhasFunc判断L280-L284避免不必要的响应体传输逐条规则改写对每条命中规则——函数型规则执行rule._func(finalBody, detailObj, util)普通规则则直接把rule.body?.value作为新 body同时收集规则携带的响应头RULE_REMOVE_MARK标记表示删除该头重新编码并 fulfill字符串结果经safeBtoa、Uint8Array结果经uint8ArrayToBase64转为 base64最终以responseCode: 200调用Fetch.fulfillRequest伪造响应L341-L346。Request 与 Response 阶段的差异在这里体现得很直接Request阶段暂停时根本没有服务端响应responseHeaders为空、Fetch.getResponseBody无意义所以改写内容只能来自规则本身普通值或函数对空val的生成逻辑响应头需要靠规则手动补全Response阶段暂停时 CDP 已携带真实responseHeaders函数中可读到它们。FirefoxfilterResponseData 响应流过滤Firefox 侧WebExtension v2不经过 debugger而是在onHeadersReceived事件中调用browser.webRequest.filterResponseData(requestId)取得响应流过滤器。核心实现是 web-request-handler.ts 的modifyReceivedBody要点前置门槛IS_SUPPORT_STREAM_FILTERENABLE_WEB_REQUEST typeof browser.webRequest.filterResponseData function定义见 browser.ts不满足直接跳过8MB 上限handleReceived中若响应带Content-Length且 ≥MAX_BODY_SIZE8 * 1024 * 1024则不做修改L319-L328流式缓冲阶段一旦累计超过 8MB也立即切为透传模式——把已缓冲的分片原样写出后续数据零拷贝直接write保证大文件不被截断也不额外吃内存L543-L564两种执行路径无函数型规则时走simple executeonstop后直接把最后一条规则的body.value编码写出并close()存在函数型规则时先缓冲全部分片onstop后合并为单个Uint8Array按encoding解码得到finalBody依次执行各函数规则detail.rawResponse指向合并后的原始字节有变化则写回改写结果否则写回原字节onerror时会把已缓冲数据 flush 后关闭避免响应体丢失编码往返入站textDecode(encoding, buffers)出站textEncodeUTF-8与 Chrome 侧同一套约定。已知问题与限制Chrome 新标签页首次访问不生效文档 Known Issues 原文On Chrome, response modifications do not take effect when accessing a site for the first time in a new tab。从源码结构看enableFetch是在tabs.onCreated/onUpdated回调中异步attachFetch.enable的而pendingTabIds只用于去重、并不会挂起请求可以推断标签页创建后发出的首个请求可能先于Fetch.enable完成而直接放行因此需要刷新或再次访问才会被拦截Firefox 下 8MB 响应体上限超过MAX_BODY_SIZE的响应不做改写直接透传无Content-Length的流式响应则依赖分片累计判断性能与下载影响文档提示该功能会影响访问速度与资源占用部分内容下载可能受影响建议只对必要 URL 配置规则并在不需要时通过 Options 页关闭modify-body开关。小结HeaderEditor 的修改响应体是一个横跨两种浏览器架构的功能Chrome 侧依赖chrome.debugger CDPFetch域通过requestStage参数实现 Request/Response 两阶段拦截并以Fetch.fulfillRequest伪造响应Firefox 侧依赖webRequest.filterResponseData的响应流过滤配合 8MB 缓冲上限与透传保护。配置时把握三个要点即可非 UTF-8 页面务必在encoding中指定正确编码它只影响解码输出恒为 UTF-8Chrome 下按是否需要读取真实响应选择body.stage自定义函数只依赖val、detail.browser、detail.rawResponse等两端共有语义并注意函数返回Uint8Array可以输出二进制内容。配合仓库中 tests/e2e/response.spec.mjs 的端到端用例可以完整验证从普通替换到函数改写的整条链路。赞分享开发工具网络【免费下载链接】HeaderEditorManage browsers requests, include modify the request headers, response headers, response body, redirect requests, cancel requests项目地址https://gitcode.com/gh_mirrors/he/HeaderEditor点击查看免费下载相关推荐Litmus pod-http-modify-body 实验详解通过代理改写 HTTP 响应 Body 的混沌故障注入Litmus pod http modify body 实验详解通过代理改写 HTTP 响应 Body 的混沌故障注入 本文围绕 Litmus 混沌实验清单中云原生运维可观测性Higress custom-response 插件完全指南自定义 HTTP 应答状态码、响应头与 BodyHigress custom response 插件完全指南自定义 HTTP 应答状态码、响应头与 Body 本篇技术指南以 Higress 开源仓库中 cuAPI网关后端云原生LLM 网关人工智能MCP 服务QuickRecorder 安装教程macOS 免费录屏不装虚拟声卡录系统声音QuickRecorder 安装教程macOS 免费录屏不装虚拟声卡录系统声音 QuickRecorder 是一款免费的开源 macOS 录屏工具基于苹果桌面应用音视频屏幕录制上一篇AzerothCore搭建指南魔兽世界私服60分钟可玩下一篇Granite-3.0-2B-Base-GGUF API接口设计RESTful服务搭建教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考