mozilla
Your Search Results

    HTTP Request Header setzen

    This article is in need of an editorial review.

    This translation is incomplete. Please help translate this article from English.

    HTTP ist eine der zentralen Webtechnologien. Neben dem eigentlichen Inhalt werden einige wichtige Informationen sowohl für die HTTP Requests als auch für die Antworten (Responses) gesetzt.

    Du kannst für jedes Request der Anwendung deine eigenen HTTP Header setzen, egal ob das Request dadurch eingeleitet wird, daß dein Code explizit einen HTTP-Kanal öffnet, ob es durch eine XMLHttpRequest Aktivität entstand, durch ein <img> Element in der Seite generiert oder gar von CSS aus gestartet wurde.

    HTTP Kanäle

    Wenn du HTTP Anfragen (Requests) und Antworten bearbeites, machst du das typischerweise mit einem nsIHttpChannel. Die nsIHttpChannel Schnittstelle besitzt eine Reihe von Eigenschaften und Methoden, von denen uns hier vor allem setRequestHeader interessiert. Diese Methode erlaubt uns, einen HTTP Request Header zu setzen.

    Es folgt Beispielcode, wie wir einen HTTP Header setzen.

    // fuegt "X-Hello: World" als Header zum Request hinzu
    httpChannel.setRequestHeader("X-Hello", "World", false);
    

    Im obenstehenden Bespielcode haben wir eine Variable httpChannel, die auf ein Objekt zeigt, das nsIHttpChannel implementiert. (Die Variable hätte aber auch irgendwie anders heißen können.)

    Die Methode setRequestHeader erwartet 3 Parameter. Der erste Parameter ist der Name des HTTP Request Headers. Der zweite Parameter ist der Wert des HTTP Request Headers. Ignoriere vorläufig den dritten Parameter, und setze ihn erst einmal immer auf false.

    In unserem Beispiel hat der HTTP Request Header, den wir hinzugefügt haben, den Namen X-Hello und den Wert World.

    HINWEIS: IWenn du deinen eigenen HTTP header einführst, MUST du ein X- vor den Namen setzen. (In unserem Beispiel ist unser neuer HTTP header X-Hello und NICHT Hello weil wir korrekterweise das X- vor unserem Namen hinzugefügt haben.)


    Dieser Hinweis ist veraltet: http://tools.ietf.org/html/rfc6648

    Benachrichtigungen

    Du wirst dich jetzt vielleicht fragen, wie man an den nsIHttpChannel kommt, wenn das HTTP Request abgeschickt wurde.

    Wenn dein eigener Code das Request erzeugt hat, dann hast du den HTTP Kanal wahrscheinlich schon. Anders erzeugte Requests fängt man mit Benachrichtigungen (notifications) ab, die sehr stark den Ereignissen oder Signalen ähneln, die man in anderen Sprachen und Frameworks findet.

    In diesem Fall müssen wir, um den nsIHttpChannel rechtzeitig vor dem Absenden des HTTP Requests zu bekommen, das "http-on-modify-request" Thema ("topic") beobachten. (Ja, "http-on-modify-request" ist eine Zeichenkette.)

    HINWEIS: Es gibt viele andere "topics" neben "http-on-modify-request", zu denen du Benachrichtigungen bekommen kannst. Zum Beispiel "http-on-examine-response" und "xpcom-shutdown". Du kannst auch deine eigenen "topics" einrichten und selber Benachrichtigungen dazu verschicken..

    Für nähere Informationen über das Benachrichtigungs-Framework und eine Liste allgemeiner Benachrichtigungs-Topics siehe Observer Notifications.

    Observer (Beobachter)

    Um zu einem Thema wie "http-on-modify-request" Benachrichtigungen zu empfangen müssen wir einen Beobachter (observer) einrichten. Ein Beobachter ist eine Komponente, die die nsIObserver Schnittstelle implementiert. Sobald der Beobachter für ein Thema registriert ist, wird es über das Thema benachrichtigt, indem seine observe Methode aufgerufen wird.

    Unten folgt der Quelltext eines Beispiel-Beobachters, der unseren Zusatz-Header "X-Hello" zu dem HTTP-Kanal hinzufügt, der der Benachrichtigung für http-on-modify-request mitgegeben wird:

    var {Cc, Ci} = require("chrome");
    var httpRequestObserver =
    {
      observe: function(subject, topic, data) 
      {
        if (topic == "http-on-modify-request") {
          var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
          httpChannel.setRequestHeader("X-Hello", "World", false);
        }
      }
    };
    
    HINWEIS: Der obenstehende Quelltext wurde verändert um wiederzugeben, daß man in einem Firefox-Add-On die Typen Components.interfaces und Components.classes nicht mehr direkt ansprechen kann, sondern die obere "require"-Codezeile nutzen muß. Deshalb steht auf dieser Seite Ci bzw. Cc, wo man früher Components.interfaces respektive Components.classes verwendet hat.
    Bitte beachte auch, daß der Code selber normalerweise in einen Block exports.main = function() { ... } eingeschlossen wird.

    Beachte dabei, daß es wichtig ist, wie viele Parameter die observe Method übergeben bekommt. Es sind 3 Parameter (Wie wir oben im Beispielcode gezeigt haben). Für das "http-on-modify-request" Thema enthält der erste Parameter (im oberen Beispiel subject genannt) den nsIHttpChannel. Aus gewissen Gründen wird er uns aber als nsISupports Objekt übergeben. Deshalb müssen wir das nsISupports in ein nsIHttpChannel umwandeln, was der Aufruf von QueryInterface für uns macht. Und sicher - Objekte von einem Typ in einen anderen umzuwandeln ist sehr häßlich und läßt etwas vermissen, was man als 'Syntaktischen Zucker' bezeichnen könnte.

    Die zweite Zeile des Codes im if-Block sollte dir bereits bekannt erscheinen. Es ist der selbe Code, den wir bereits vorher verwendet hatten, um den HTTP Request Header hinzuzufügen.

    Der Name des Objektes -- httpRequestObserver -- ist unwichtig. Wir hätten es benennen können, wie es uns gefällt.

    Registrierung

    Nachdem wir den Beobachter aufgesetzt haben, müssen wir ihn registrieren. In unserem Fall möchten wir ihn für das Thema "http-on-modify-request" registrieren. Das können wir mit dem untenstehenden Code tun.

    var observerService = Cc["@mozilla.org/observer-service;1"]
                                    .getService(Ci.nsIObserverService);
    observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
    

    Der erste Ausdruck holt das Objekt, das uns Registrierungen zu Themen durchführen läßt, zu denen wir Benachrichtigungen erhalten wollen.

    Der Befehl in der zweiten Zeile führt die eigentliche Registrierung durch. Es bedeutet: Wir wollen, daß httpRequestObserver (durch Aufrufen seiner observe Methode) benachrichtigt wird, wenn ein "http-on-modify-request" Thema stattfindet (von dem wir wissen, daß es direkt vor jedem HTTP Request passiert).

    Abmeldung

    Du solltest den Beobachter vor dem Beenden abmelden, um mögliche Speicherlecks zu vermeiden. Einen Beobachter meldet man mit einem Aufruf von nsIObserverService.removeObserver wie folgt ab:

    observerService.removeObserver(httpRequestObserver, "http-on-modify-request");

    Zusammengefaßtes Beispiel

    Hier ist eine leicht andere Variante unseres httpRequestObserver Objektes. Während die vorherige Version die wir gezeigt haben für das Lernen anschaulich sein sollte, möchte man den Code in echten Anwendungen vielleicht eher wie folgt aufbauen:

    var httpRequestObserver =
    {
      observe: function(subject, topic, data)
      {
        if (topic == "http-on-modify-request") {
          var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
          httpChannel.setRequestHeader("X-Hello", "World", false);
        }
      },
    
      get observerService() {
        return Cc["@mozilla.org/observer-service;1"]
                         .getService(Ci.nsIObserverService);
      },
    
      register: function()
      {
        this.observerService.addObserver(this, "http-on-modify-request", false);
      },
    
      unregister: function()
      {
        this.observerService.removeObserver(this, "http-on-modify-request");
      }
    };
    

    Dieses Objekt hat benutzerfreundliche register() und unregister() Methoden. Damit braucht man für die Aktivierung nur noch folgendes aufzurufen:

    httpRequestObserver.register();
    

    Du solltest auch nicht vergessen, vor den Beenden den Beobachter abzumelden:

    httpRequestObserver.unregister();
    

    Und das war's schon.

    XPCOM Komponenten

    Du mußt den http-on-modify-request Beobachter einmal pro Anwendung registrieren (Nicht einmal pro Fenster!). Das bedeutet, daß du die Implementierung des Beobachters in eine XPCOM Komponente anstelle eines overlays packen solltest. Wenn du Gecko2 (Firefox4) unterstützen willst, mußt du deine javascript Komponente so registrieren wie hier beschrieben: https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0#JavaScript_components.

    var headerName  = "X-hello";
    var headerValue = "world";
    
    function LOG(text)
    {
        //    var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
        //    consoleService.logStringMessage(text);
    }
    
    function myHTTPListener() { }
    
    myHTTPListener.prototype = {
        
      observe: function(subject, topic, data)
      {
          if (topic == "http-on-modify-request") {
    
              LOG("----------------------------> (" + subject + ") mod request");
    
              var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
              httpChannel.setRequestHeader(headerName, headerValue, false);
              return;
          }
    
    
          if (topic == "profile-after-change") {
    
              LOG("----------------------------> profile-after-change");
    
              var os = Components.classes["@mozilla.org/observer-service;1"]
                                 .getService(Components.interfaces.nsIObserverService);
    
              os.addObserver(this, "http-on-modify-request", false);
              return;
          }
      },
     
      QueryInterface: function (iid) {
            if (iid.equals(Components.interfaces.nsIObserver) ||
                iid.equals(Components.interfaces.nsISupports))
                return this;
            
            Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
            return null;
        },
    };
    
    var myModule = {
        registerSelf: function (compMgr, fileSpec, location, type) {
    
            var compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
            compMgr.registerFactoryLocation(this.myCID,
                                            this.myName,
                                            this.myProgID,
                                            fileSpec,
                                            location,
                                            type);
    
    
              LOG("----------------------------> registerSelf");
    
            var catMgr = Components.classes["@mozilla.org/categorymanager;1"].getService(Components.interfaces.nsICategoryManager);
            catMgr.addCategoryEntry("app-startup", this.myName, this.myProgID, true, true);
        },
    
    
        getClassObject: function (compMgr, cid, iid) {
    
              LOG("----------------------------> getClassObject");
    
            return this.myFactory;
        },
    
        myCID: Components.ID("{9cf5f3df-2505-42dd-9094-c1631bd1be1c}"),
    
        myProgID: "@dougt/myHTTPListener;1",
    
        myName:   "Simple HTTP Listener",
    
        myFactory: {
            QueryInterface: function (aIID) {
                if (!aIID.equals(Components.interfaces.nsISupports) &&
                    !aIID.equals(Components.interfaces.nsIFactory))
                    throw Components.results.NS_ERROR_NO_INTERFACE;
                return this;
            },
    
            createInstance: function (outer, iid) {
    
              LOG("----------------------------> createInstance");
    
              return new myHTTPListener();
            }
        },
    
        canUnload: function(compMgr) {
            return true;
        }
    };
    
    function NSGetModule(compMgr, fileSpec) {
        return myModule;
    }
    

    Gute Praktiken für Datenschutz und Sicherheit

    Ein Anwendungsfall für das Setzen eines anwendungsspezifischen HTTP Request Headers ist, wenn ein bestimmter Webauftritt prüfen können soll, ob der Browser ein bestimmtes Plugin / Add-On / Erweiterung installiert hat.

    Eine gute Praxis dazu ist, wenn man diesen spezifischen HTTP Header (beispielsweise "X-site.net-extension") nicht immer sendet, sondern nur dann, wenn man HTTP Requests an diese eine spezifische Webaddresse schickt. Nicht gleich von vorn herein allen besuchten Webservern mitzuteilen, welche Erweiterungen installiert sind, ist gut sowohl für den Datenschutz (weil so die Identifikation und Nachverfolgung von Nutzern anhand ihres Browserprofils erschwert wird), als auch für die Sicherheit (Angreifer kennen so manche Schwachstelle von bestimmten Browsererweiterungen).

    Bei Beachtung dieser Datenschutz- und Sicherheitspraktiken sieht der Quelltext dann so aus:

    observe: function(subject, topic, data)
     {
       if (topic == "http-on-modify-request") {
         var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
         if (/site.net/.test(httpChannel.originalURI.host)) {
              httpChannel.setRequestHeader("X-Hello", "World", false);
         }
       }
     },
    

    Document Tags and Contributors

    Contributors to this page: asgalon
    Last updated by: asgalon,