Javascript 在Firefox扩展中更改HTTP响应

Javascript 在Firefox扩展中更改HTTP响应,javascript,firefox-addon,Javascript,Firefox Addon,如何更改Firefox扩展中的HTTP响应主体?我用下面的代码在Inspect response observer和nsIStreamListener对象上设置了http。在我获取数据、解析数据并对其进行修改后,如何将修改后的响应推回到firefox浏览器?例如,假设我在启用扩展的情况下访问Google.com,扩展应该拦截响应并将每次出现的“Google”更改为“goggle”。因此,当页面加载时,用户将看到“goggle”无处不在 function TmSteroidsObserver()

如何更改Firefox扩展中的HTTP响应主体?我用下面的代码在Inspect response observer和nsIStreamListener对象上设置了http。在我获取数据、解析数据并对其进行修改后,如何将修改后的响应推回到firefox浏览器?例如,假设我在启用扩展的情况下访问Google.com,扩展应该拦截响应并将每次出现的“Google”更改为“goggle”。因此,当页面加载时,用户将看到“goggle”无处不在

function TmSteroidsObserver()
{
  this.register();
}


TmSteroidsObserver.prototype = {
  observe: function(subject, topic, data) {

    if (topic == "http-on-examine-response") {

    }
    else if (topic == "http-on-modify-request") {
       var channel = subject.QueryInterface(Components.interfaces.nsIChannel);
       var listener = new StreamListener(channel);
    }

  },

  register: function() {
    var observerService = Components.classes["@mozilla.org/observer-service;1"]
                                .getService(Components.interfaces.nsIObserverService);
    observerService.addObserver(listener, "http-on-modify-request", false);
    observerService.addObserver(listener, "http-on-examine-response", false);
  },

  unregister: function() {
    var observerService = Components.classes["@mozilla.org/observer-service;1"]
                            .getService(Components.interfaces.nsIObserverService);
    observerService.removeObserver(this, "http-on-modify-request");
    observerService.removeObserver(this, "http-on-examine-response");
  },

  QueryInterface : function(aIID) {
    if (aIID.equals(Components.interfaces.nsISupports) ||
        aIID.equals(Components.interfaces.nsIObserver))
      return this;
    throw Components.results.NS_NOINTERFACE;
  }

}

function StreamListener(channel) {

    channel.notificationCallbacks = listener;
    channel.asyncOpen(listener, null);

}

StreamListener.prototype = {
  mData: "",
  mChannel: null,

  // nsIStreamListener
  onStartRequest: function (aRequest, aContext) {
    this.mData = "";
  },

  onDataAvailable: function (aRequest, aContext, aStream, aSourceOffset, aLength) {
    var scriptableInputStream = 
      Components.classes["@mozilla.org/scriptableinputstream;1"]
        .createInstance(Components.interfaces.nsIScriptableInputStream);
    scriptableInputStream.init(aStream);

    this.mData += scriptableInputStream.read(aLength);
  },

  onStopRequest: function (aRequest, aContext, aStatus) {
    if (Components.isSuccessCode(aStatus)) {
      // request was successfull
      this.mCallbackFunc(this.mData);
    } else {
      // request failed
      this.mCallbackFunc(null);
    }

    this.mChannel = null;
  },

  // nsIChannelEventSink
  onChannelRedirect: function (aOldChannel, aNewChannel, aFlags) {
    // if redirecting, store the new channel
    this.mChannel = aNewChannel;
  },

  // nsIInterfaceRequestor
  getInterface: function (aIID) {
    try {
      return this.QueryInterface(aIID);
    } catch (e) {
      throw Components.results.NS_NOINTERFACE;
    }
  },

  // nsIProgressEventSink (not implementing will cause annoying exceptions)
  onProgress : function (aRequest, aContext, aProgress, aProgressMax) { },
  onStatus : function (aRequest, aContext, aStatus, aStatusArg) { },

  // nsIHttpEventSink (not implementing will cause annoying exceptions)
  onRedirect : function (aOldChannel, aNewChannel) { },

  // we are faking an XPCOM interface, so we need to implement QI
  QueryInterface : function(aIID) {
    if (aIID.equals(Components.interfaces.nsISupports) ||
        aIID.equals(Components.interfaces.nsIInterfaceRequestor) ||
        aIID.equals(Components.interfaces.nsIChannelEventSink) || 
        aIID.equals(Components.interfaces.nsIProgressEventSink) ||
        aIID.equals(Components.interfaces.nsIHttpEventSink) ||
        aIID.equals(Components.interfaces.nsIStreamListener))
      return this;

    throw Components.results.NS_NOINTERFACE;
  }
};

您可以使用nsITraceableChannel截获响应

您应该根据需要修改可用的数据,并将其传递给innerListener的OnDataAvailable

下面的链接将帮助您更好地理解这一点


观察员服务只需给您的听众打电话。Firefox将接收请求、呼叫您的侦听器并发送响应。请参阅Mozilla文档

对于希望在Firefox Quantum中实现这一点的未来读者,这里有。使用长文档的方法,我能够可靠地更改(临时)插件的
background.js
中所需的内容,如下所示:

browser.webRequest.onBeforeRequest.addListener(
    function fixenator(details) {
        let filter = browser.webRequest.filterResponseData(details.requestId);
        let decoder = new TextDecoder("utf-8");
        let encoder = new TextEncoder();
        let str = '';

        filter.ondata = event => {
            str += decoder.decode(event.data, {stream: true});
        };

        filter.onstop = event => {
            str = str.replace(/searchPattern/g, 'replace pattern');
            filter.write(encoder.encode(str));
            filter.close();
        }

        return {};
    },
    {
        urls: ['https://example.com/path/to/url']
        //, types: ['main_frame', 'script', 'sub_frame', 'xmlhttprequest', 'other'] // optional
    }
    , ['blocking']
);