43

我已经尝试了很长时间,但没有很好的结果。

var myObserver = {
    observe: function(subject, topic, data)
    {
        if (topic == "http-on-examine-response") 
        {   
             //  implement later
        } 
        else if(topic == "http-on-modify-request") 
        {
             //  implement later
        }
   },

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

var obs = new Service("observer-service", "ObserverService");
obs.addObserver(myObserver, "http-on-modify-request", false);

基本上,在 上http-on-modify-request,我知道如何检查 URI,找出它与哪个窗口(如果有)相关联,以及一堆其他东西。我不知道如何重定向请求,我知道从这里可以实现,因为我可以在发出任何请求之前获得一个 nsIHttpChannel 。

有谁知道该怎么做?:/我已经断断续续地尝试了几个星期,但一无所获。

4

4 回答 4

3

我们可以通过用一个新的覆盖来做到这一点nsiHttpChannel,这样做有点复杂,但幸运的是插件https-everywhere实现了这一点来强制一个 https 连接。

https-everywhere的源代码可在此处获得

所需的大部分代码都在文件中

[ IO Util.js] [ ChannelReplacement.js]

只要我们设置了 Cc、Ci 等基本变量并xpcom_generateQI定义了函数,我们就可以单独使用上述文件。

var httpRequestObserver =
{ 
  observe: function(subject, topic, data) {
    if (topic == "http-on-modify-request") {

        var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);     
        var requestURL = subject.URI.spec;

        if(isToBeReplaced(requestURL))  {

            var newURL = getURL(requestURL);        
             ChannelReplacement.runWhenPending(subject, function() {
                    var cr = new ChannelReplacement(subject, ch);
                    cr.replace(true,null);
                    cr.open();
                });
        }
    }

  },

  get observerService() {
    return Components.classes["@mozilla.org/observer-service;1"]
                     .getService(Components.interfaces.nsIObserverService);
  },

  register: function() {
    this.observerService.addObserver(this, "http-on-modify-request", false);

  },

  unregister: function() {
    this.observerService.removeObserver(this, "http-on-modify-request");

  }
};


httpRequestObserver.register();

该代码将替换请求而不是重定向。

虽然我已经很好地测试了上面的代码,但我不确定它的实现。据我所知,它复制了请求通道的所有属性并将它们设置为要覆盖的通道。之后以某种方式使用新通道提供原始请求所请求的输出。

PS我看过一个SO帖子,其中建议了这种方法。

于 2012-09-26T12:43:23.910 回答
1

我的印象是您无法在此级别执行此操作 - 我尝试了各种外部“欺骗”调用创建 nsIHttpChannel 的代码的方法(帖子末尾的示例)。

我的建议是,如果您想要重定向,请联系频道的所有者窗口(99% 的时间都有效),并指示它重定向。我知道它的行为不会相同,但是由于我不确切知道您为什么要这样做,因此在外部(对用户而言)这似乎与您所要求的相同。

这是我尝试的基础知识:

if(aTopic == "http-on-examine-response") {                                                                                     
            var request = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);                                                      

            if(!request.URI.spec.match("^http://www.apple.com/")) {                                                          
                var ios = Components.classes["@mozilla.org/network/io-service;1"]                                                             
                    .getService(Components.interfaces.nsIIOService);                                                                          
                var ch = ios.newChannel("http://www.apple.com/", null, null);                                                                 

                var listener = {                                                                                                              
                    QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannelEventSink]),                                                         
                    onDataAvailable: function() {},                                                                                           
                    onStopRequest: function() {},                                                                                             
                    onStartRequest: function() {}                                                                                             
                };                                                                                                                            

                ch.asyncOpen(listener,null);                                                                                                  

                var eventSink = request.notificationCallbacks.getInterface(Ci.nsIChannelEventSink);                                           
                eventSink.asyncOnChannelRedirect(request,ch,Ci.nsIChannelEventSink.REDIRECT_INTERNAL,function() {});                          
            } 
于 2012-05-26T01:13:29.077 回答
0

我是这样做的:停止nsIHttpChannel事件"http-on-modify-request",获取当前窗口的浏览器对象,调用browser.loadURI.

var utils = require("sdk/window/utils");

function needsRedirect(url) {
    // to be implemented
    return true;
}

function generateNewUrl(url) {
    // to be implemented
    return "http://www.example.com/";
}

Cc["@mozilla.org/observer-service;1"]
    .getService(Ci.nsIObserverService)
    .addObserver({
        observe: function(subject, topic, data) {
            var channel = subject.QueryInterface(Ci.nsIHttpChannel);
            var url = channel.originalURI.spec;
            if (needsRedirect(url)) {
                //stop
                channel.cancel(Cr.NS_BINDING_ABORTED);

                //redirect
                var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
                var domWin = channel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
                var browser = gBrowser.getBrowserForDocument(domWin.top.document);
                browser.loadURI(generateNewUrl(url));

            }
        }
    }, "http-on-modify-request", false);
于 2013-11-27T09:47:38.593 回答
0

在测试某些东西时,我创建了其他答案中提到的通道替换逻辑的精简版本(请参阅此要点)。

一般的想法似乎是将所有关键属性转移到新通道,从旧通道中删除回调,这样操作就不会导致页面加载,然后关闭旧通道。

通过一些修改,可以更改文档加载的页面 URI 或保持原样。

警告:这只是一个快速加载几页的技巧,我还没有深入测试它,在某些情况下它可能会中断。我怀疑 HTTPS Everywhere 更复杂是有原因的。

于 2015-12-17T08:45:50.360 回答