xml捕获需区分xhr/fetch响应与dom嵌入两类来源:前者须拦截网络请求并解析响应体,后者应直接提取textcontent;混用方法将导致失败。

XML 捕获必须区分来源:XHR 还是 DOM?
浏览器插件无法“全局监听所有 XML”,必须明确目标来源。常见两类:一是页面通过 fetch 或 XMLHttpRequest 加载的 XML 响应(如 RSS、SOAP 接口);二是页面 DOM 中已存在的 <?xml> 声明或 <root><item>...</item></root> 结构。前者需拦截网络请求,后者可直接查询 DOM —— 方法完全不同,混用会导致捕获失败。
- DOM 中的 XML 通常只是普通 HTML 元素(如
<pre class="brush:php;toolbar:false;"></code> 里放的 XML 字符串),没有解析为 XML 文档对象,不能用 <code>responseXML</code></li> <li>XHR/fetch 的 XML 响应,只有在 <code>responseType === 'document'</code> 或服务端返回 <code>Content-Type: application/xml</code> 且浏览器自动解析时,才可能拿到 <code>responseXML</code></li> <li>现代 fetch 默认不解析 XML,<code>response.text()</code> 是最稳妥的获取原始 XML 字符串方式</li> </ul> <H3>拦截 XHR/fetch 并提取 XML 响应体</H3> <p>需在 content script 中重写原生方法,捕获响应内容。注意:fetch 拦截比 XHR 更复杂,因它是 Promise 驱动,需包装 <code>response.clone()</code> 避免 body 被读取多次。</p> <pre class="brush:php;toolbar:false;">const originalFetch = window.fetch; window.fetch = function(...args) { return originalFetch(...args).then(response => { // 只处理明确返回 XML 的响应 const contentType = response.headers.get('content-type'); if (contentType && /application\/xml|text\/xml/i.test(contentType)) { const cloned = response.clone(); cloned.text().then(xmlStr => { // 此处发送 XML 字符串到后台脚本或上传接口 chrome.runtime.sendMessage({ type: 'xml-captured', url: response.url, xml: xmlStr.slice(0, 102400) // 限制长度防爆内存 }); }).catch(() => {}); } return response; }); };</pre> <ul> <li>不要在 fetch 拦截中直接调用 <code>response.text()后返回新 Response —— 会破坏原始响应流 -
chrome.runtime.sendMessage需在 manifest.json 中声明"externally_connectable"或仅用于内部通信 - 部分站点使用
blob:URL 或 Service Worker 拦截请求,此时 content script 无法捕获,需改用webRequestAPI(需"webRequest"权限和"host_permissions")
从 DOM 提取 XML 字符串的可靠方式
当 XML 以文本形式嵌入 HTML(如 <script type="application/xml"></script>、<pre class="xml"></code>、或注释节点),用 <code>textContent</code> 最安全。避免用 <code>innerHTML</code>,防止误解析标签。</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/code/10454" title="通吃客零食网整站 for Shopex"><img
src="https://img.php.cn/upload/webcode/000/000/020/176216580836240.jpg" alt="通吃客零食网整站 for Shopex" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/code/10454" title="通吃客零食网整站 for Shopex">通吃客零食网整站 for Shopex</a>
<p>第一步】:将安装包中所有的文件夹和文件用ftp工具以二进制方式上传至服务器空间;(如果您不知如何设置ftp工具的二进制方式,可以查看:(http://www.shopex.cn/support/qa/setup.help.717.html)【第二步】:在浏览器中输入 http://您的商店域名/install 进行安装界面进行安装即可。【第二步】:登录后台,工具箱里恢复数据管理后台是url/sho</p>
</div>
<a href="/xiazai/code/10454" title="通吃客零食网整站 for Shopex" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
<pre class="brush:php;toolbar:false;">// 匹配常见的 XML 容器
const xmlCandidates = [
'script[type="application/xml"]',
'script[type="text/xml"]',
'pre.xml',
'code.xml',
'textarea[lang="xml"]'
].map(sel => document.querySelectorAll(sel)).flat();
xmlCandidates.forEach(el => {
let xmlStr = el.textContent.trim();
// 简单校验:开头是否含 <?xml 或 <root 类似结构
if (/^<\?xml\s|^\s*<\w+[\s>]/.test(xmlStr)) {
chrome.runtime.sendMessage({
type: 'xml-from-dom',
selector: el.outerHTML.substring(0, 50),
xml: xmlStr.slice(0, 102400)
});
}
});</pre>
<ul>
<li>DOM 提取无法捕获动态生成的 XML(如 JS 拼接后写入 <code>innerHTML 但未挂载到文档)
/^ 仍有效;但纯二进制 XML(如 gzip 压缩)无法通过 DOM 提取
run_at: "document_idle" 的 content script上传前必须处理的三个实际问题
直接 fetch(uploadUrl, { method: 'POST', body: xmlStr }) 很容易失败。真实环境中需确认以下三点:
- 服务端是否要求
Content-Type: application/xml?还是接受text/plain或表单字段?不匹配会返回 400 - XML 字符串是否含非法控制字符(如 \u0000–\u0008)?上传前建议用
xmlStr.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '')清理 - 跨域上传时,若服务端未设置
Access-Control-Allow-Origin,需走 background script 中转(background 不受 CORS 限制)
最易被忽略的是编码一致性:XML 声明中的 encoding="GBK" 和实际传输字节不匹配,会导致服务端解析乱码。插件中统一用 UTF-8 处理和上传,除非服务端明确要求其他编码。









