You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展:拦截修改JSON payload并前置处理DOM渲染的技术问询

问题描述

我正在为自有网站开发一款Chrome扩展,目标是让用户在浏览器端补全数据(隐私友好,无需后端参与逻辑,也不访问用户数据),期望流程如下:

  • 用户请求内容时,后端仅返回字符串"Animal",对应JSON为{"userWants": "Animal"}(出于隐私考虑,我方不知道用户偏好猫咪);
  • 浏览器接收该JSON后,将userWants字段值修改为"Cat";
  • 最终页面显示"Cat"而非默认的"Animal"。

我尝试过以下JS代码(可忽略):

console.log("Im here!");
function modifyJSON(json) {
// Modify the JSON object here as needed
// Example: json.title = "Modified Title";
json.userWants = "Cat";
return json;
}

const originalFetch = window.fetch;
window.fetch = async function (...args) {
const response = await originalFetch.apply(this, args);

    if (response.url.endsWith("/fetch-json")) {
        const clonedResponse = response.clone();
        const json = await response.json();
        const modifiedJSON = modifyJSON(json);
    
        return new Response(JSON.stringify(modifiedJSON), {
            status: clonedResponse.status,
            statusText: clonedResponse.statusText,
            headers: clonedResponse.headers,
        });
    } else {
        return response;
    }

};

现在想了解:能在JSON payload到达DOM元素前拦截并修改内容,最终显示"Cat"的相关技术、API或实现方法。


可行实现方法

1. 优化Fetch API拦截(你当前的方案)

你的现有思路是对的,但要确保拦截逻辑在页面脚本之前生效,同时完善异常处理:

  • 在扩展manifest.json里设置"run_at": "document_start",让内容脚本优先于页面脚本加载,避免页面fetch先被初始化;
  • 增加错误捕获,防止解析JSON失败导致请求异常;
  • 只针对目标接口做修改,不影响其他请求。

优化后的代码示例:

(function() {
    const originalFetch = window.fetch;
    window.fetch = async function(...args) {
        try {
            const response = await originalFetch.apply(this, args);
            // 仅拦截目标接口
            if (response.url.endsWith("/fetch-json")) {
                const clonedResp = response.clone();
                let jsonData;
                try {
                    jsonData = await clonedResp.json();
                    // 修改指定字段
                    if (jsonData.userWants) {
                        jsonData.userWants = "Cat";
                    }
                    // 返回修改后的响应
                    return new Response(JSON.stringify(jsonData), {
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.headers
                    });
                } catch (e) {
                    // 解析JSON失败,直接返回原响应
                    return response;
                }
            }
            return response;
        } catch (e) {
            // 请求失败,抛出原错误
            throw e;
        }
    };
})();

2. 拦截XMLHttpRequest(兼容旧页面)

如果你的网站仍在使用XMLHttpRequest而非fetch,需要单独做拦截:

(function() {
    const originalXHR = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(method, url) {
        this.addEventListener('load', function() {
            if (url.endsWith("/fetch-json") && (this.responseType === '' || this.responseType === 'json')) {
                try {
                    const jsonData = JSON.parse(this.responseText);
                    if (jsonData.userWants) {
                        jsonData.userWants = "Cat";
                        // 重写响应文本和response对象
                        Object.defineProperty(this, 'responseText', { value: JSON.stringify(jsonData) });
                        if (this.response) {
                            Object.defineProperty(this, 'response', { value: jsonData });
                        }
                    }
                } catch (e) {}
            }
        });
        originalXHR.apply(this, arguments);
    };
})();

3. Chrome扩展webRequest API(底层拦截)

用Chrome扩展的webRequest API可以在请求到达页面之前就修改响应,不需要注入内容脚本到页面:

  1. 在manifest.json中添加权限:
{
    "permissions": ["webRequest", "webRequestBlocking", "https://your-domain.com/*"],
    "background": {
        "service_worker": "background.js"
    }
}
  1. 在background.js中实现拦截:
// 移除Content-Length头,避免修改内容后长度不匹配
chrome.webRequest.onHeadersReceived.addListener(
    function(details) {
        const contentType = details.responseHeaders.find(h => h.name.toLowerCase() === 'content-type');
        if (contentType && contentType.value.includes('application/json') && details.url.endsWith("/fetch-json")) {
            return {
                responseHeaders: details.responseHeaders.map(h => {
                    if (h.name.toLowerCase() === 'content-length') return undefined;
                    return h;
                }).filter(Boolean)
            };
        }
    },
    {urls: ["https://your-domain.com/*"]},
    ["blocking", "responseHeaders"]
);

// 拦截响应体并修改
chrome.webRequest.onResponseStarted.addListener(
    async function(details) {
        if (details.url.endsWith("/fetch-json")) {
            // 获取原响应内容
            const response = await fetch(details.url, {
                headers: details.requestHeaders,
                method: details.method,
                credentials: 'include'
            });
            const jsonData = await response.json();
            jsonData.userWants = "Cat";
            // 创建修改后的Blob并返回
            const blob = new Blob([JSON.stringify(jsonData)], {type: 'application/json'});
            const url = URL.createObjectURL(blob);
            return {redirectUrl: url};
        }
    },
    {urls: ["https://your-domain.com/*"]},
    ["blocking"]
);

注意:这种方法需要处理跨域和缓存问题,适合复杂场景。

4. DOM修改兜底方案(拦截请求失败时用)

如果以上方法都无法生效,可以在内容渲染到DOM后立即修改,虽然可能有短暂闪烁,但兼容性最好:

// 监听DOM变化
const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
            // 处理文本节点
            if (node.nodeType === Node.TEXT_NODE && node.textContent.includes("Animal")) {
                node.textContent = node.textContent.replace("Animal", "Cat");
            }
            // 处理元素节点的子内容
            else if (node.nodeType === Node.ELEMENT_NODE) {
                node.querySelectorAll("*").forEach(el => {
                    if (el.textContent.includes("Animal")) {
                        el.textContent = el.textContent.replace("Animal", "Cat");
                    }
                });
            }
        });
    });
});

// 启动观察者
observer.observe(document.body, {
    childList: true,
    subtree: true,
    characterData: true
});

内容的提问来源于stack exchange,提问作者NotYourClone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:35:33