☰
微信网页版UA伪装扩展开发:Manifest V3下declarativeNetRequest实战
2026/10/7 2:54:54 网站建设 项目流程

简介:Wechat-need-web 是一款免费开源的浏览器插件,专为想在电脑上使用微信网页版的用户打造,支持 Edge、Chrome 等 Chromium 内核浏览器,解决官方网页端登录受限、无法直接打开的问题。微信网页版界面简洁,仅保留基础聊天功能,适合随开随关的轻度办公用户,文字、图片、表情包发送、截图、文件传输助手、新消息声音提醒、查找联系人群聊等常用功能齐全,朋友圈与视频号则不在其中。资源包共 7 个文件,以 4 个 png 图标、2 个 json 配置文件和 1 个规则集文件为主,整体仅 22KB,体积轻巧,解压后将插件文件夹拖入浏览器扩展安装页即可完成部署。目前已有 5638 人学习下载,适合希望免安装、低占用使用微信网页端的办公人群参考使用。

1. 微信网页版被拦在门外:Wechat-need-web 到底解决了谁的刚需

你在 Chrome 或 Edge 里打开微信网页版,扫码登录后页面转了两圈,弹回来一句「请在微信客户端打开链接」,或者干脆白屏。这不是网络问题,也不是账号问题,是微信服务端在入口处做了一层 UA(User-Agent)判断——它认得出你用的是不是微信内置浏览器。Wechat-need-web 这个浏览器扩展要干的事很直接:在 Chromium 内核浏览器发起请求时,把跟微信相关的域名请求头伪装成微信内置浏览器的样子,让网页版微信以为自己在微信里跑。

它适合三类人:一是在电脑上想用网页版微信但不想装客户端的;二是做前端或自动化测试,需要在 Chrome、Edge 里调试微信网页逻辑的;三是用 Linux 或特殊环境,微信客户端不好装,只能走浏览器这条路。核心机制不复杂,但落地时会碰到 Manifest V3 的声明式网络请求规则、UA 覆盖范围、Cookie 隔离这几个硬骨头。下面按「原理 → 装法 → 参数 → 避坑 → 进阶」的顺序拆开讲,每一步都能照着复现。

2. 先搞懂微信是怎么认出「你不是微信浏览器」的

2.1 UA 判断发生在哪一层

微信网页版的入口校验不在前端 JS,而在服务端。你请求wx.qq.com或wx.qq.com/cgi-bin/...时,服务端读User-Agent请求头,匹配里面有没有MicroMessenger这个标识。有,放行;没有,返回一个引导页让你去客户端打开。这个判断在 Nginx 或网关层就完成了,前端根本来不及干预。

所以浏览器扩展要做的不是改页面 DOM,而是在请求发出之前把User-Agent改掉。这里有个关键点:改 UA 不能全局改,否则你访问其他网站也会带着微信标识,轻则被识别为异常,重则触发风控。正确做法是按域名匹配,只对*.qq.com、*.weixin.qq.com这类微信相关域名生效。

2.2 Manifest V3 下的两种改法

Chrome 从 Manifest V2 过渡到 V3 之后,webRequestBlocking权限被大幅收紧,普通扩展不能再随意拦截并修改请求头。目前可行的路径有两条:

第一条是declarativeNetRequest,在manifest.json里声明规则,由浏览器内核直接执行请求头替换。这是官方推荐方式,性能好,但规则是静态声明的,动态调整需要调 API 更新动态规则。

第二条是chrome.debuggerAPI,附加到标签页后用 CDP(Chrome DevTools Protocol)的Network.setUserAgentOverride改 UA。这种方式更灵活,但会弹调试提示条,体验差一些。

Wechat-need-web 这类扩展通常走第一条路。下面给一个最小可用的declarativeNetRequest规则示例:

{ "manifest_version": 3, "name": "Wechat-need-web", "version": "1.0.0", "permissions": [ "declarativeNetRequest", "declarativeNetRequestWithHostAccess" ], "host_permissions": [ "*://*.qq.com/*", "*://*.weixin.qq.com/*" ], "declarative_net_request": { "rule_resources": [ { "id": "wechat_ua_rules", "enabled": true, "path": "rules.json" } ] } }

这段manifest.json声明了三件事:申请declarativeNetRequest权限、限定只对微信相关域名生效、把规则文件指向rules.json。host_permissions里的通配符决定了扩展能改哪些域名的请求,写宽了会误伤,写窄了微信某些子域可能漏掉。

2.3 rules.json 里到底写了什么

规则文件是核心,每条规则包含匹配条件、优先级和动作。下面是一个针对微信 UA 的规则示例:

[ { "id": 1, "priority": 1, "action": { "type": "modifyHeaders", "requestHeaders": [ { "header": "User-Agent", "operation": "set", "value": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/116.0.0.0 Mobile Safari/537.36 MicroMessenger/8.0.40.2420(0x28002837) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64" } ] }, "condition": { "urlFilter": "||qq.com", "resourceTypes": ["main_frame", "sub_frame", "xmlhttprequest"] } } ]

action.type是modifyHeaders,表示修改请求头。requestHeaders里把User-Agent用set操作替换成微信内置浏览器的 UA 字符串。condition.urlFilter用||qq.com匹配所有 qq.com 及其子域。resourceTypes限定只对主文档、子框架和 XHR 请求生效,图片、样式表这些不改,减少性能开销。

提示:UA 字符串里的MicroMessenger/8.0.40.2420版本号不用追最新,微信服务端只校验MicroMessenger关键字是否存在,版本号写个合理的即可。写太老的版本反而可能触发兼容性提示。

3. 在 Edge 和 Chrome 里把扩展跑起来

3.1 开发者模式加载未打包扩展

Wechat-need-web 这类扩展如果没上架商店,或者你想自己改规则,就得用开发者模式加载。Chrome 和 Edge 的路径几乎一样:

Chrome 地址栏输入chrome://extensions/,Edge 输入edge://extensions/。右上角打开「开发者模式」开关,左上角出现「加载已解压的扩展程序」按钮,选中包含manifest.json的文件夹即可。

加载后如果图标没出现,检查manifest.json里有没有声明action字段。Manifest V3 里browser_action已经废弃,要用action:

{ "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } } }

default_popup是点击图标后弹出的小窗口,通常放开关和状态显示。default_icon按尺寸给图标,缺尺寸浏览器会自动缩放,但建议都提供。

3.2 验证规则有没有生效

加载完扩展后,打开wx.qq.com,按 F12 打开开发者工具,切到 Network 面板,刷新页面,点第一个文档请求,看 Request Headers 里的User-Agent是不是变成了带MicroMessenger的那串。

如果没变,按这个顺序排查:第一,确认扩展已启用且没有报错,chrome://extensions/里点「错误」按钮看有没有规则解析失败;第二,确认host_permissions覆盖了当前域名,wx.qq.com属于*.qq.com,应该能匹配;第三,看rules.json的urlFilter写法,||qq.com匹配的是域名后缀,wx.qq.com能命中,但如果你写的是qq.com不带||,可能匹配不到子域。

3.3 用 declarativeNetRequest 的动态规则做调试

静态规则改一次要重新加载扩展,调试不方便。可以用动态规则在运行时更新,适合边调边试:

// 在 background service worker 里执行 async function updateWechatUARule(uaString) { const existingRules = await chrome.declarativeNetRequest.getDynamicRules(); const ruleIds = existingRules.map(r => r.id); await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: ruleIds, addRules: [ { id: 1001, priority: 1, action: { type: 'modifyHeaders', requestHeaders: [ { header: 'User-Agent', operation: 'set', value: uaString } ] }, condition: { urlFilter: '||qq.com', resourceTypes: ['main_frame', 'sub_frame', 'xmlhttprequest'] } } ] }); }

getDynamicRules先拿到现有动态规则,updateDynamicRules里removeRuleIds清掉旧的,addRules加新的。这样改 UA 不用重载扩展,在 Service Worker 控制台调一下就行。注意动态规则有数量上限,Chrome 目前是 5000 条,正常用远够。

注意:Manifest V3 的 Service Worker 会休眠,动态规则存在浏览器本地,休眠不影响已注册的规则,但如果你在 Service Worker 里用内存变量存状态,休眠后会丢,重要状态要写chrome.storage。

4. 参数怎么设、范围怎么定:几个容易翻车的地方

4.1 UA 字符串的构造要点

微信内置浏览器的 UA 有几个固定特征:包含MicroMessenger/、包含WeChat/、平台标识(Android 或 iPhone)。服务端主要认MicroMessenger,但有些接口会读WeChat/后面的版本做功能降级判断。

一个稳妥的 Android 微信 UA 模板:

Mozilla/5.0 (Linux; Android 13; {设备型号}) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/{Chrome版本} Mobile Safari/537.36 MicroMessenger/{微信版本} WeChat/{微信版本} NetType/{网络类型} Language/zh_CN

{设备型号}随便填个主流机型,{Chrome版本}填个 100 以上的值,{微信版本}填 8.0.x,{网络类型}填 WIFI 或 4G。不要填太离谱的值,比如 Chrome 版本写 50,可能触发「浏览器版本过低」的提示。

4.2 urlFilter 的匹配范围

urlFilter的语法跟 Adblock 类似,||表示域名锚定,|表示开头或结尾锚定,*是通配符。常见写法对比:

写法匹配范围适用场景
`qq.com`
`weixin.qq.com`
`https://wx.qq.com/`仅 https 且路径以 / 开头
*://*.qq.com/*所有协议所有子域最宽,慎用

我一般先用||qq.com跑通,确认没问题后再收窄到具体子域。收太早容易漏掉登录跳转用的中间域名,导致扫码后回调失败。

4.3 resourceTypes 选哪些

resourceTypes决定规则对哪些请求生效。微信网页版的登录流程涉及主文档跳转、XHR 接口调用、可能还有 iframe 嵌入。建议至少包含:

  • main_frame:主页面导航
  • sub_frame:iframe 里的请求
  • xmlhttprequest:AJAX 接口

script、stylesheet、image这些静态资源一般不需要改 UA,加上去只会增加匹配开销。但如果你发现某个 JS 文件加载后前端又用navigator.userAgent做了一次判断,那就得把script也加上——不过这种情况更推荐在前端注入脚本覆盖navigator.userAgent,而不是改请求头。

4.4 Cookie 和登录态隔离

改了 UA 之后,微信服务端可能给你下发一套跟微信浏览器绑定的 Cookie。这些 Cookie 如果和你正常浏览其他 qq.com 页面的 Cookie 混在一起,可能出现登录态串扰。常见做法是在扩展里对微信域名做 Cookie 分区,或者干脆用一个独立的浏览器 Profile 专门跑微信网页版。

Chrome 和 Edge 都支持多 Profile,建一个专门的工作 Profile,只装这个扩展,登录态互不干扰。这是最省事的隔离方案,比在扩展里手动管理 Cookie 可靠。

5. 避坑与排查:那些让我重装过三次浏览器的问题

5.1 现象:扩展加载后报「Rules file is invalid」

原因:rules.json格式错误,常见的是 JSON 尾逗号、id重复、priority没写。declarativeNetRequest对规则格式校验很严,一个字段不对整个文件都不加载。

解决:把rules.json贴到 JSON 校验工具里过一遍,确认id全局唯一,priority是正整数。改完在chrome://extensions/里点扩展的刷新按钮重新加载。

5.2 现象:UA 改了但微信还是提示「请在微信客户端打开」

原因:大概率是urlFilter没匹配到实际请求的域名。微信登录可能先跳open.weixin.qq.com,再跳wx.qq.com,中间还有res.wx.qq.com加载资源。如果只写了||wx.qq.com,前面的跳转就没覆盖到。

解决:打开 Network 面板,把登录流程走一遍,看每个请求的域名,把漏掉的加到urlFilter或host_permissions里。或者直接用||qq.com兜底,跑通后再逐步收窄。

5.3 现象:Edge 里扩展生效,Chrome 里不生效

原因:两个浏览器的扩展是独立安装的,在 Edge 里加载了不代表 Chrome 里也有。另外 Edge 和 Chrome 对declarativeNetRequest的支持版本有差异,老版本 Edge 可能不支持某些规则字段。

解决:分别在edge://extensions/和chrome://extensions/里确认扩展已加载且启用。检查浏览器版本,Chromium 内核低于 100 的建议升级,declarativeNetRequestWithHostAccess权限在旧版本里行为不一致。

5.4 现象:改完 UA 后其他网站登录异常

原因:host_permissions写太宽,比如写了*://*/*,导致所有网站的请求都被改了 UA,银行、邮箱这类对 UA 敏感的服务会触发风控。

解决:host_permissions严格限定在微信相关域名,不要图省事写通配。如果确实需要临时全局测试,测完立刻改回来。

5.5 现象:Service Worker 里chrome.declarativeNetRequest报 undefined

原因:manifest.json里没声明declarativeNetRequest权限,或者声明了但没在permissions数组里,写到了host_permissions里。

解决:确认permissions数组包含"declarativeNetRequest"或"declarativeNetRequestWithHostAccess"。前者用于静态规则,后者用于需要 host 权限的动态规则。两个都加上最稳妥。

6. 进阶:把 UA 伪装做成可切换的开关

跑通之后,我习惯把 UA 伪装做成可开关的,而不是一直生效。原因很简单:平时浏览 qq.com 其他页面时带着微信 UA 没必要,还可能触发一些页面的移动端适配,布局变窄。做成开关,只在打开微信网页版时启用。

实现思路是在popup.html里放一个 checkbox,状态存chrome.storage.local,Service Worker 监听状态变化,调updateDynamicRules增删规则。核心代码:

// popup.js document.getElementById('toggle').addEventListener('change', async (e) => { const enabled = e.target.checked; await chrome.storage.local.set({ wechatUAEnabled: enabled }); // 通知 service worker 更新规则 chrome.runtime.sendMessage({ type: 'TOGGLE_UA', enabled }); }); // 初始化时读取状态 chrome.storage.local.get('wechatUAEnabled', (result) => { document.getElementById('toggle').checked = !!result.wechatUAEnabled; });
// background.js (service worker) chrome.runtime.onMessage.addListener(async (msg) => { if (msg.type === 'TOGGLE_UA') { if (msg.enabled) { await updateWechatUARule(WECHAT_UA_STRING); } else { const rules = await chrome.declarativeNetRequest.getDynamicRules(); await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: rules.map(r => r.id) }); } } });

popup.js负责 UI 和状态存储,background.js负责根据状态增删规则。chrome.storage.local在 Service Worker 休眠后依然保留,不会丢状态。

验证开关是否生效,可以在chrome://extensions/里点 Service Worker 的「检查视图」,在控制台里调chrome.declarativeNetRequest.getDynamicRules()看当前规则列表。开的时候应该有一条 id 1001 的规则,关的时候列表为空。

还有一个细节:微信网页版有些接口会校验Referer,如果 Referer 不是微信域,也可能被拦。这种情况要在规则里同时改Referer头,把它 set 成https://wx.qq.com/。不过大部分场景只改 UA 就够了,Referer 校验是少数接口才有的,遇到再加。

最后说个我踩过的坑:有段时间微信网页版登录后频繁掉线,查了半天以为是 UA 问题,后来发现是扩展同时改了Origin头,导致 WebSocket 握手失败。declarativeNetRequest默认不会改Origin,但如果你的规则里用了modifyHeaders且没限定 header 名,可能误伤。规则里requestHeaders数组只写你要改的那一个头,别偷懒写通配。

这套方案我从 Manifest V2 时代一路跟到 V3,中间因为权限模型变化重写过两次。现在的declarativeNetRequest方案虽然声明式写起来啰嗦,但稳定性和性能比老的webRequest好,也不会有「扩展已损坏」的提示。如果你只是想在电脑上安安静静用网页版微信,按上面的步骤走一遍,半小时能跑通。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询