首页 / 资讯中心 / 文章详情

ModHeader修改HTTP请求头实战:配置、场景与排错

ModHeader修改HTTP请求头实战:配置、场景与排错 ★ FEATURED ARTICLE
前后端联调的时候你有没有遇到过这种对话你把页面截图发过去对方回一句“你请求头里带个 X-Trace-Id 我再看看”或者“你本地把 Referer 换成正式域名的值试一下”。这时候你要是去改代码、加拦截器、重新打包十几分钟就没了。我现在的做法是直接点开浏览器工具栏上一个灰色小图标勾选一行刷新页面三秒钟出结果。这个工具就是 ModHeader——一个专门用来修改 HTTP 请求头和响应头的浏览器扩展国内不少开发者管它叫“请求头修改利器”。它解决的问题非常具体让前端在不改一行业务代码、不重启服务、不动构建配置的前提下临时给某个域名的请求加上、删掉、或者覆盖掉指定的头字段。适用人群也比想象中宽做接口联调的前端、验证鉴权逻辑的后端、测多端适配的测试同学甚至做 SEO 和活动页的同学都会用到它。但它同时又是个“看起来简单、用起来到处是坑”的工具我见过太多人装完之后发现规则不生效然后在群里发一句“这玩意儿是不是假的”。下面这些内容就是我把这些年用它踩过的坑、总结的配置套路完整摊开讲一遍。1. 我为什么把 ModHeader 放在浏览器工具栏第一格1.1 一个后端说“你带上这个头试试”的下午先说个很典型的场景。某次做一个订单列表的分页联调后端在网关层加了一个开关头只有带上X-Feature-Flag: order-v2才会走新的聚合逻辑。我在本地开发环境跑着前端服务接口是通过环境变量指向测试环境的。要验证这个分支理论上我有三条路改环境配置文件重启 dev server、在请求拦截器里临时写死一个 header、或者用 Postman 单独把这个接口调一遍。三条路都有代价。第一种最慢重启一次几十秒而且容易把本地其它配置带歪第二种会在代码里留下脏东西稍不留神就提交上去了review 的时候被同事点名第三种看不到页面的真实渲染结果只能验证接口返回的 JSON前端拿到数据之后表格会不会崩、分页器会不会错位全都没法确认。ModHeader 走的是第四条路它在浏览器发出请求之前把这一行头塞进去。页面还是那个页面代码还是那份代码但请求已经带上了我想要的东西。你在开发者工具的 Network 面板里能看到它在服务端日志里也能看到它跟真实请求没有区别。这就是它的定位——不是替代代码而是缩短“验证一个猜想”的路径。写代码是永久的验证是临时的临时的事情就该用临时的工具干别用永久的成本去解决一个五分钟的问题。1.2 它到底改的是什么从浏览器发请求的三个层次说起很多人用不明白 ModHeader根子上是没搞清楚浏览器发一个请求会经过哪些环节。我把它简化成三层来看。第一层是页面自己写的头比如你的fetch或axios里设置的Content-Type、自定义的 token 头。第二层是浏览器自动附加的头比如User-Agent、Accept、Referer、Origin、Cookie这些你没有写浏览器替你补上。第三层是浏览器在收到响应后做的安全检查比如跨域校验。ModHeader 主要动的是前两层——它在请求真正离开浏览器之前介入把指定的头覆盖掉、追加进去、或者删掉。所以User-Agent、Referer这类浏览器自动加的头它也能改这是它比“在代码里加 header”强的地方。但它动不了第三层。这一点非常关键后面我会单独用一节讲清楚为什么改响应头不能解决跨域问题。你现在只需要记住一句话ModHeader 改的是“请求长什么样”不是“浏览器允不允许”。提示如果你只是想看看某个接口带了某个头会返回什么用 curl 更快只有当你需要“页面上的真实渲染结果”时ModHeader 的价值才凸显出来。2. Profile、Filter、Header 三件套的关系打开面板你大概会有点懵上面一排是配置名中间是一堆键值对下面还有一个筛选框。这三块东西各自管什么是新手最容易糊掉的部分。2.1 Profile 是“环境”不是“开关”Profile配置档本质上是一个场景容器。我一般按“这件事情是为什么做的”来建 Profile而不是按“改了什么”。举几个我自己的命名习惯本地-测试环境鉴权、移动端UA验证、活动页Referer、紧急-接口降级观测。为什么按场景命名而不是按字段命名因为一个场景往往会同时涉及多个头比如验证移动端适配你既要改User-Agent可能还要改Accept里的一些偏好项甚至加一个X-Requested-With。如果按字段建 Profile一个场景你要来回切好几次按场景建一次切换全搞定。另一个好处是关闭成本低。Profile 上通常有个开关可以整体启用/停用你验证完直接关掉整个 Profile不会漏掉某一条规则忘了关。我见过最惨的案例是有人在 Profile 里留了一个指向测试环境的Authorization忘了关第二天在正式环境排查另一个问题怎么调怎么不对查了一个上午。至于 Profile 之间能不能同时生效不同版本行为有差异我的建议是永远保持在任何一个时刻只开一个 Profile把多场景合并成一个 Profile 的多条规则别指望工具帮你处理并发那是给自己找麻烦。2.2 Filter 决定这条规则对哪些请求生效Filter 是 ModHeader 里最被低估的功能。不加 Filter 的规则是全局的你改一个User-Agent浏览器里所有标签页、所有域名的请求全都会带上它——包括你自己的邮箱、文档站、甚至扩展商店。这会带来两个后果一是可能把别的网站搞坏二是噪音太大你自己在 Network 面板里都找不到想看的那条。Filter 的写法一般支持通配符和简单的模式匹配。我常用的几类写法示例含义适用场景*://api.example-dev.com/*匹配某域名下所有请求整个环境切换*://*.example.com/api/*匹配子域下的接口路径主域 子域联调*/api/order/*只匹配特定接口单接口调试*://localhost:*/*本地服务的任意端口本地开发关键点是尽量把域名写全。只写路径*/api/*看着方便实际上会把所有站点里带/api/的请求全盖上出了问题你根本想不到是它。我现在的习惯是每条规则必带域名宁可多建两个 Profile。还有一点容易被忽略Filter 匹配的是完整 URL包括查询参数。所以如果你的接口 URL 上带了一长串?t时间戳用精确匹配基本没用老老实实用通配。2.3 Header 值的三种操作覆盖、追加、删除同一个头字段ModHeader 能做的事其实有三种很多人只用过第一种。覆盖是最常用的你填一个值原来页面代码里的值或者浏览器自动加的值就被替换掉。比如把User-Agent换成某个机型。追加用于那些本身是列表的头典型的是Accept、Accept-Language、Cache-Control。有些版本提供了追加模式把新值加到已有值的后面而不是替换掉。如果找不到追加选项不同版本界面不一样可以手动写成原值, 新值的形式效果差不多。删除用得少但关键时刻救命。比如你想验证“不带 Cookie 的情况下接口会不会返回未登录”就可以把Cookie这个头删掉或者某个中间件因为收到了多余的X-Forwarded-For走了不同的分支你也需要把它摘掉。删除通常是把值留空并且选用对应的操作类型具体交互以你手上的版本为准。注意删除Cookie这类操作对当前标签页的所有请求生效如果你同时登着后台管理系统会把你自己踢下线。删之前先确认 Filter 收窄到了目标域名。3. 六个高频场景的具体配置拆法这一节我按“我实际用它干过什么”来组织每个场景给配置思路和注意事项你可以直接照着抄。3.1 多环境切换把域名和环境标记分开管大部分团队的环境是靠域名区分的开发、测试、预发、正式各一个。切换环境通常是改前端的环境变量重启服务很慢。但如果你只是想在页面上看看某个环境的数据其实不一定要改代码。思路是页面还是你本地这份但让它把请求打到另一个环境去。这时候需要的不只是改头还要改请求地址。ModHeader 本身有重定向相关的能力不同版本叫法不一样在面板里找 Redirect 类似的功能把localhost:8080/api/*重定向到api.example-test.com/api/*同时补上目标环境需要的鉴权头。我必须提醒一句跨域限制在这时候会跳出来。目标环境如果没有对你本地页面开放跨域请求会被浏览器拦下。这时候你能做的只有让服务端配置放行别指望扩展能绕过——原因见 3.6 节。如果你的目标只是“贴一个环境标记头”那就简单得多加一行X-Env: test之类的自定义头剩下的交给网关去路由。这种用法最干净我最推荐。3.2 登录态注入Authorization 与自定义 Token 头这是使用频率最高的场景也是最容易出事的地方。典型痛点是你本地页面的登录态失效了或者你想用另一个账号的身份去看页面。重新走一遍登录流程太麻烦尤其是那种要短信验证码的。这时候把正式请求里抓到的 token 直接写进 ModHeader 的头配置里页面一刷新就是那个身份。配置要注意字段名必须和服务端读的完全一致。常见的几种写法差别很大# 常见的三种鉴权头格式字段名和前缀都不能猜 Authorization: Bearer eyJhbGciOi... Authorization: eyJhbGciOi... X-Access-Token: eyJhbGciOi...我踩过的坑是Bearer后面的空格。有些服务端解析逻辑写得糙多一个空格少一个空格直接返回 401而你在 Network 面板里看请求头肉眼看不出区别。排查的时候把Authorization的值复制出来用cat -A之类的方式看有没有隐藏字符比盯着屏幕强。另外token 一般有有效期。你要是配好之后隔了两小时才发现接口全 401别怀疑工具坏了先去看看 token 是不是过期了。我现在的做法是在 Profile 名字后面直接标上过期时间比如测试账号A-token(6/12前)一眼就知道该不该换。3.3 移动端 UA 模拟与页面适配验证改User-Agent是最直观的用法。你手上没有真机或者只是想快速看看某个 H5 页面在移动端 UA 下的首屏布局把 UA 换成一个常见机型的字符串刷新页面就行。但这里有个认知需要纠正改 UA 只是骗过了服务端和前端 JS 里的 UA 判断它不会让浏览器变成手机。视口宽度、触摸事件、设备像素比、媒体查询这些都不受影响。所以如果你要验证的是响应式布局正确做法是用开发者工具里的设备模拟那个手机图标而不是改 UA改 UA 只适合验证“服务端根据 UA 返回不同内容”这类逻辑。实际配置我一般这么写# 请求头配置示例值仅作格式参考 User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1还有一个配套技巧有些服务端会根据Accept-Language返回不同语言的文案你可以同时加上这一行一次验证“移动端 英文”的组合。这种组合验证是纯用代码改很难做到的因为你改一处要重新构建一次。3.4 Referer 与防盗链、防爬策略的本地验证Referer这个头平时没人注意一旦你要验证防盗链、来源白名单、或者第三方回调的校验逻辑它就是核心。场景是这样的服务端配置了“只有来自 A 域名的请求才允许下载这个资源”。你在本地调试页面上引用这个资源死活拿不到。这时候把Referer覆盖成 A 域名请求立刻通。配置上有个细节Referer的格式是完整 URL别只写域名。有些校验逻辑会取Referer的路径部分做匹配你只写https://a.example.com是不带路径的可能会挂。注意这里验证的是“你自己系统的校验逻辑是否符合预期”属于正常的开发测试行为。别拿它去访问不属于你的资源那是另一回事跟工具无关。同时提醒一个反直觉的点Referer在某些情况下会被浏览器直接忽略或者改写比如从 HTTPS 页面跳转到 HTTP 页面时默认不发送。你改的值如果涉及协议降级可能压根发不出去这时候排查方向要换。3.5 缓存控制与强刷Cache-Control 与 Pragma 的组合前端最经典的问题之一改了代码刷新页面没变化。九成是缓存。清缓存、开无痕、改配置折腾一圈。用 ModHeader 可以直接给请求加禁止缓存的头Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache为什么两个都要加因为Pragma是老规范遗留的字段一些老的中间件和 CDN 节点还认它而Cache-Control是新规范。两个一起写覆盖面最广。这是很多文档里不会提的组合拳。但我要泼一盆冷水请求头的no-cache管不了浏览器本地已经存下的资源。如果你的静态资源是带 hash 的浏览器根本不发请求直接从内存缓存拿你加什么头都没用。这种情况还是老老实实用“清空缓存并硬性重新加载”或者开发者工具里勾上禁用缓存。ModHeader 在这里真正有用的场景是验证 CDN 或者网关的缓存策略。比如你想确认某个接口是不是被缓存了加上Cache-Control: no-cache再请求如果返回内容和之前一样但响应头里的缓存命中标记变了就说明确实是缓存层在起作用。这是纯诊断用途比瞎猜快得多。3.6 响应头改写CORS 调试与安全头效果观察这一节我要说点可能让人失望的实话。ModHeader 面板里一般也能配响应头Response Headers。很多人第一反应是跨域报错了我把Access-Control-Allow-Origin改成*不就行了不行。原因在于浏览器的执行顺序。跨域校验是浏览器在拿到响应之后、交给页面 JS 之前做的安全判定而扩展改写响应头是在更靠后的环节。等扩展把Access-Control-Allow-Origin改掉的时候浏览器早就已经判定这个响应不合规并且拦截了。你改的是一个“已经被判定为不可用”的响应。那响应头改写到底能干嘛两个正经用途一是观察。你想知道服务端到底返回了哪些安全相关的头比如X-Frame-Options、Content-Security-Policy、Strict-Transport-Security把它们改成某个值之后看看页面行为有没有变化。比如把X-Frame-Options去掉验证你的页面是不是真的能被嵌到 iframe 里——这是验证“配置是否生效”的常用手段前提是服务端本来就没有配置这个头或者你只是想看“如果没有这个头会怎样”。二是本地 Mock。你在本地起一个静态服务模拟响应用响应头改写补齐一些字段让页面的判断逻辑跑通。这属于搭建调试环境不涉及任何绕过。跨域这件事正解只有一个让服务端在预检和正式响应里正确返回允许的来源。你要做的是把请求头里的Origin抓出来给后端看而不是想办法把它糊过去。4. Filter 的匹配写法与优先级陷阱4.1 通配与正则什么时候用哪个大多数版本的 Filter 支持通配符*部分版本支持正则。我的选择标准很简单能用通配就不用正则。原因是正则写错的时候不会报错它只是不匹配然后你花半小时怀疑人生。通配符写错最多是匹配多了你能立刻从 Network 面板里看出来。通配符的用法就是*代表任意字符写的时候把“不变的部分”写全把“变的部分”用*替代。比如*://api.example.com/v1/order/* *://*.example.com/api/user/* *://localhost:*/api/*正则的话只在需要“排除”或者“多个不同模式合并”的时候用比如^https://api\.example\.com/v[12]/(order|user)/。用正则的时候务必先在浏览器控制台里用new RegExp(...).test(你的URL)验证一遍别直接往扩展里填。4.2 多条规则命中同一请求时会发生什么这是最隐蔽的坑。假设你有两条规则同时改User-Agent一条在 Profile 的顶层一条带了 Filter哪个生效不同版本行为可能不一样但大多数情况下是后写的覆盖先写的或者带 Filter 的优先级更高。我的做法是从根源上避免这个问题同一个头字段在一个 Profile 里只出现一次。需要针对不同 URL 用不同值的就拆成不同 Profile用完切换。如果你接手了别人的配置发现行为诡异第一件事就是把所有规则的 Filter 列出来看看有没有重叠。我一般会在配置旁边写一行注释如果工具不支持注释就写在团队文档里标明每条规则的作用范围。4.3 一个可复用的配置模板下面这份不是官方导出格式是我自己维护的一份配置清单用来在团队里同步“这个 Profile 里到底放了什么”。新人拿到之后照着在面板里填一遍比截图清晰得多{ profile: 本地联调-订单服务, enabled: true, requestHeaders: [ { name: X-Feature-Flag, value: order-v2, action: set }, { name: X-Trace-Id, value: local-debug-001, action: set }, { name: Cache-Control, value: no-cache, action: set } ], filters: [ *://api.example-test.com/v1/order/*, *://localhost:*/api/order/* ], notes: 用于验证订单聚合逻辑验证完记得关闭 }注意最后那个notes字段。工具本身可能不支持写备注但这个习惯必须养成——每一条临时配置都要有“什么时候该关掉”的说明否则它迟早会在某个你想不到的场合坑你一次。5. 规则不生效时的排查链路5.1 第一步永远是看开发者工具里有没有这个头不要凭感觉判断。打开开发者工具切到 Network找到那条请求点开看 Request Headers展开完整列表搜你要的那个字段名。如果头在那里说明 ModHeader 正常工作了问题出在服务端或者业务逻辑去查别的地方。 如果头不在才是工具的问题按下面的顺序往下剥。这一步能省掉一半的无效排查。我见过太多人反过来了先怀疑工具把配置删了重配三遍最后发现是接口缓存了旧响应。5.2 按层次往下剥扩展是否启用、Profile 是否激活、Filter 是否匹配确认头没出现之后按这个顺序查每一步都有明确判据第一层扩展是不是全局开着。有些浏览器在无痕窗口里默认禁用扩展你在无痕里调半天其实扩展根本没加载。还有些企业环境会限制扩展权限点开图标是灰的。第二层Profile 是不是当前激活的那个。面板上可能有好几个 Profile只有一个在生效。名字很像的时候特别容易切错。我的做法是给每个 Profile 起差异极大的名字别用test1test2这种。第三层Filter 是不是匹配上了。这一层最容易出问题。把 Filter 临时清空看头是不是出现了——如果清空之后就正常那就是 Filter 写法的问题。常见错误是协议写错http写成https、端口没写、路径少了斜杠、或者 URL 上有查询参数导致精确匹配失败。第四层是不是有另一条规则覆盖了它。回到 4.2 节说的情况把头字段名全局搜一遍看有没有重复定义。这个剥洋葱的顺序我用了很多年九成的问题能在前三层定位。5.3 那些“改了但没用”的假象预检请求、Service Worker、缓存有时候头确实发出去了Network 面板里能看到但接口还是报错。这时候要看的是另外几个东西。预检请求。当你加了一个自定义头跨域请求会先发一个OPTIONS请求做预检。如果服务端没有正确处理OPTIONS比如直接返回 405正式请求根本不会发出去。你在面板里只能看到那个OPTIONS是红的看不到你期望的GET。很多人以为是头没加上其实是服务端没配预检。判断方法看 Network 面板里有没有那个OPTIONS点开看它的 Request Headers 里有没有Access-Control-Request-Headers里面会列出来你要加的那个自定义头——它清楚地告诉你“我知道你要加这个头但对方没同意”。Service Worker。如果页面注册了 Service Worker 并且接管了 fetch请求的实际发起路径会变。有些情况下你看到的请求是 SW 发起的Header 的修改行为可能不符合预期。判断方法Network 面板里看请求的 Initiator 列如果是service worker相关字样先去 Application 面板把这个 SW 注销掉再测。缓存。304 响应或者从磁盘缓存直接返回的请求你在面板里看到的头可能是旧的。勾上 “Disable cache” 再测一遍。这三个假象我几乎每隔几个月就会遇到一次尤其是预检那个每次都要重新想一遍才反应过来。5.4 常见故障对照表把上面这些整理成一张表出问题的时候直接对号入座现象最可能原因快速验证方法头完全没出现扩展未启用 / Profile 未激活点开图标看状态切换 Profile 试只有部分请求有这个头Filter 写得太窄清空 Filter 再试头出现了但值是旧的另一条规则覆盖 / 浏览器缓存搜重复字段名勾 Disable cache加了自定义头后请求变成 OPTIONS 且失败跨域预检未通过看 OPTIONS 的响应头有没有放行改了响应头但页面行为没变浏览器安全检查早于扩展改写换一个不影响安全策略的头验证无痕窗口里配置无效扩展在无痕下被禁用检查扩展的无痕权限设置头时有时无页面有 Service Worker 接管注销 SW 后重测6. 配置的沉淀、共享与边界6.1 导出导入与团队共享的约定ModHeader 一般提供配置的导出和导入能力格式通常是 JSON 或者一个配置文件。这个功能在小团队里非常有用新人入职不用听你口头讲“你要加哪几个头”直接把配置文件发过去导入一分钟配好。但我建议在共享之前做两件事清掉所有真实凭证以及在文件名里标注用途和有效期。前者是为了安全后者是为了让半年后的人知道这东西还能不能用。我们内部的做法是维护一份“环境调试配置清单”的文档每个 Profile 一段说明用途、包含哪些头值用占位符、Filter 范围、什么情况下应该关掉。真正导出的配置文件只在内部分享不进代码仓库。为什么因为配置文件里很容易残留 token一旦进了仓库就是永久泄露。6.2 什么不该往里放密钥与生产环境的红线这条我想说得重一点。不要把正式环境的长期凭证放进 ModHeader。这个工具的设计前提是“临时验证”它没有任何加密保护配置文件是明文导出是明文浏览器同步账号之后还可能跟着同步到别的设备上。放一个有效期两小时的临时 token 可以接受放一个长期有效的密钥就是给自己埋雷。不要把规则指向正式环境做写操作。读接口看看数据没问题但如果你配了一条会命中正式环境写接口的规则一次误操作可能就是真实的数据变更。我的习惯是任何 Filter 里带正式域名的配置一律在名字里加[只读]前缀而且用完立刻删掉不留着“下次可能还要用”。不要在共享设备上留配置。这个不用多解释。6.3 用完就关一个必须养成的习惯前面提过好几次这里正式说一下。ModHeader 最大的风险不是它改错了什么而是它悄悄改了你还不知道。一个忘了关的User-Agent规则可能让你在某个后台管理系统里看到一个完全不同的界面然后你以为是系统出 bug 了报给运维运维查了半天说“我们这边没问题啊”。我的做法是把“关闭”变成动作的一部分验证完成先关 Profile再关浏览器标签页。顺序不能反因为很多人关标签页的时候会顺手把整个窗口关掉以为事情结束了实际上 Profile 的启用状态是被记住的下次打开还在。如果你用的是支持快捷键的版本把“切换 Profile 启用状态”绑一个顺手的组合键比去点图标快得多也就更容易坚持。最后分享一个我自己的小习惯我永远保留一个名字叫全空的 Profile里面一条规则都没有。每当我觉得“哪里不对劲但又说不清”第一件事就是切到全空刷新一次。如果问题消失了那八成就是某个残留规则在作祟如果问题还在那就安心去查业务代码不用再怀疑工具了。这个空 Profile 帮我省下的时间比这个工具本身带来的还多。
阅读完成 · 觉得有帮助?
咨询建站