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

如何修改Chrome扩展中WebSocket的onmessage回调以拦截服务端消息?

问题:Chrome扩展中拦截WebSocket接收消息的实现方案

我正在开发一款Chrome扩展,通过注入脚本替换页面中的WebSocket,仅用于拦截并记录服务端发送的消息。发送消息的拦截可通过重写WebSocket的.send()方法轻松实现,但接收消息的拦截则较为复杂。目前原应用会为socket.onmessage设置自身的回调函数,我已在原型中拦截了这个作为参数传入的函数,但无法修改它,否则会导致功能异常;替换该函数会使其依赖脱离原匿名函数的作用域(WebSocket在该匿名函数中实例化)。请问是否可通过修改传入原型的回调函数来实现此类日志记录?

相关代码

WebSocket包装类核心片段

var WebSocket = function (url, protocols) {
    'native';
    if (window.location.protocol === 'https:' &&
        url.lastIndexOf('ws:', 0) === 0) {
        // 防呆处理:HTTPS页面不能使用明文WS连接,直接触发异常
        var ws = new Wrapped(url, protocols);
        if (ws) {
            ws.close();
        }
    }
    
    Object.defineProperties(this, {
       'onmessage': {
            get: function () {
                return getWrappedProperty(this, 'onmessage', null);
            },
            set: function (value) { // <------ 这里的value就是每次WebSocket收到消息时会被调用的回调函数
                setWrappedProperty(this, 'onmessage', value);
            }
        },

属性操作工具函数

var getWrappedProperty = function (wrapper, prop, defaultValue) {
    var wrapped = map.get(wrapper);
    if (!wrapped) {
        return defaultValue;
    }
    
    if (wrapped instanceof Wrapped) {
        return wrapped[prop];
    }
    
    return wrapped.properties.hasOwnProperty(prop) ?
        wrapped.properties[prop] :
        defaultValue;
};

/**
 * 设置指定属性的值
 *
 * @param wrapper   包装实例
 * @param prop      属性名
 * @param value     要设置的值
 */
var setWrappedProperty = function (wrapper, prop, value) {
    if (value instanceof Function) {
        value = value.bind(wrapper);
    }
    
    var wrapped = map.get(wrapper);
    if (!wrapped) {
        return;
    }
    
    if (wrapped instanceof Wrapped) {
        wrapped[prop] = value;
    } else {
        wrapped.properties[prop] = value;
    }
};
解决方案

完全可以通过包装原回调函数的方式实现日志记录,不需要替换原函数或者修改其作用域。核心思路是在onmessage的setter或setWrappedProperty中,对传入的原回调进行包裹:先执行日志逻辑,再调用原回调,同时完整保留原函数的作用域和绑定关系。

方案一:修改onmessage的setter

直接在onmessage属性的set方法中处理回调包装:

set: function (value) {
    if (typeof value === 'function') {
        // 保存原回调,创建包裹函数
        const originalCallback = value;
        value = function(event) {
            // 插入你的日志记录逻辑
            console.log('WebSocket收到消息:', event.data);
            // 调用原回调,确保this指向和参数完全一致
            return originalCallback.call(this, event);
        };
    }
    setWrappedProperty(this, 'onmessage', value);
}

方案二:在setWrappedProperty中统一处理

如果想在工具函数中统一拦截onmessage属性,可以修改setWrappedProperty:

var setWrappedProperty = function (wrapper, prop, value) {
    // 仅针对onmessage回调做包装
    if (prop === 'onmessage' && typeof value === 'function') {
        const originalCallback = value;
        value = function(event) {
            // 执行日志记录
            console.log('WebSocket接收消息:', event.data);
            // 调用原回调,保留上下文
            return originalCallback.call(this, event);
        };
    }
    
    if (value instanceof Function) {
        value = value.bind(wrapper);
    }
    
    var wrapped = map.get(wrapper);
    if (!wrapped) {
        return;
    }
    
    if (wrapped instanceof Wrapped) {
        wrapped[prop] = value;
    } else {
        wrapped.properties[prop] = value;
    }
};

关键细节说明

  1. 保留原作用域:通过originalCallback.call(this, event)确保原回调执行时的this指向不变,不会脱离原匿名函数的作用域。
  2. 不破坏原功能:原回调的业务逻辑完全保留,只是在其执行前后插入日志代码,不会导致原应用功能异常。
  3. 兼容绑定关系:工具函数中原有的value.bind(wrapper)逻辑会自动处理包裹后函数的上下文绑定,确保和原回调的绑定行为一致。

这种方式不需要修改原回调函数本身,而是通过包装层实现无侵入式的日志拦截,完美解决你遇到的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:27:28