Setting HTTP request headers
出典: MDC
HTTP は Web の中核を成す技術の一つです。実際のコンテンツに加え、HTTP ヘッダによっていくつかの重要な情報が HTTP リクエストとレスポンスの両方で渡されます。
アプリケーションが作成するどんなリクエストに対しても、独自の HTTP ヘッダを加える事ができます。そのリクエストがあなたのコードで明示的に HTTP チャンネルを開くことによって開始されたリクエストであっても、また XMLHttpRequest の活動や、コンテンツ内の <img> タグ、さらに例え CSS からのものであったとしても、それは可能です。
目次 |
[編集] HTTP チャンネル
HTTP リクエストとレスポンスを扱う時には、大抵は nsIHttpChannel を扱います。nsIHttpChannel インターフェイスにはたくさんのプロパティやメソッドがありますが、ここで重要なメソッドは setRequestHeader です。このメソッドを使って HTTP リクエストヘッダを設定する事ができます。
下は HTTP ヘッダを設定するコードの例です。
// リクエストに "X-Hello: World" ヘッダを加える
httpChannel.setRequestHeader("X-Hello", "World", false);
このコードの httpChannel という変数は、nsIHttpChannel を実装したオブジェクトを示しています。(変数名はどんなものでも結構です。)
setRequestHeader メソッドは 3 つのパラメータを取ります。1 つめは HTTP リクエストヘッダの名前で、2 つめは HTTP リクエストヘッダの値です。3 つめのパラメータに関しては今のところ無視して、常に false にしておきます。
このサンプルコードでは X-Hello という名前の HTTP リクエストヘッダが追加され、この HTTP リクエストヘッダの値は World となっています。
注: 独自の HTTP ヘッダを作成する場合には、名前の前に X- を付けなければなりません。(上のサンプルコードでもちゃんと名前の前に X- を追加しているため、作成した HTTP ヘッダは Hello ではなく X-Hello となっています。)
[編集] 通知
ここでおそらく、HTTP リクエストが開始された時にどうやって nsIHttpChannel を取得するのかという疑問が出てくるでしょう。
あなたのコードによってリクエストが開始された場合には、おそらく既に取得できているでしょう。その他のリクエストを捕捉するには、通知 を使います。これは他の言語やフレームワークではイベント やシグナル と呼ばれるものと同じようなものです。
具体的に言えば、HTTP リクエストが作られる直前に nsIHttpChannel を取得するには "http-on-modify-request" トピックを監視 (observe) する必要があります。("http-on-modify-request" は文字列です。)
注: 通知を受けられるトピックは "http-on-modify-request" の他にもたくさんあります。例えば "http-on-examine-response" や "xpcom-shutdown" などです。また、独自のトピックを作り出したり、自分で通知を送る事も可能です。
通知のフレームワークや一般的な通知トピックのリストについてのより詳しい情報を得るには Observer Notifications を参照して下さい。
[編集] オブザーバ
あるトピック ("http-on-modify-request" など) についての通知を得るには、オブザーバ (observer) を作成しなければなりません。オブザーバは nsIObserver インターフェイスを実装したコンポーネントです。あるトピックに対してオブザーバが登録されると、オブザーバは observe メソッドが呼ばれる事によってそのトピックについての通知を受けます。
下のコードは http-on-modify-request の通知によって渡されたチャンネルに "X-Hello" という独自のヘッダを追加するオブザーバの例です。
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
httpChannel.setRequestHeader("X-Hello", "World", false);
}
}
};
observe メソッドが取るパラメータの数が重要です。このメソッドは (上のサンプルコードにあるように) 3 つのパラメータを取ります。"http-on-modify-request" トピックに対しては、1 つめのパラメータ (上のコードでは subject) は nsIHttpChannel になります。ただしこれは nsISupports として渡されます。なので nsISupports から nsIHttpChannel に変換しなければならず、QueryInterface を呼び出すことによってこれを行っています。
if ブロックの 2 行目のコードは既にご存知でしょう。この記事の最初の方で HTTP リクエストヘッダを追加するのに使ったコードと同じものです。
このオブジェクトの名前 (httpRequestObserver) は重要ではありません。好きな名前を付けて結構です。
[編集] 登録する
オブザーバを作成したら、それを登録する必要があります。今回の場合は、オブザーバを "http-on-modify-request" トピックに対して登録しようとしています。これは以下のコードによって可能です。
var observerService = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
1 つめの文で、通知を受けたいトピックにオブザーバを登録するためのオブジェクトを取得しています。
2 つめの文では実際に登録を行っています。 "http-on-modify-request" トピック (それぞれの HTTP リクエストの直前に起こる) が発生したときに、httpRequestObserver が (observe メソッドが呼び出されることによって) 通知を受けられるようにしています。
[編集] 登録を解除する
アプリケーションの終了時にはオブザーバの登録を解除するべきです。これを怠るとメモリリークが引き起こされる可能性があります。オブザーバの登録を解除するには、次のように nsIObserverService.removeObserver を使ってください。
observerService.removeObserver(httpRequestObserver, "http-on-modify-request");
[編集] XPCOM コンポーネント
http-on-modify-request オブザーバは、アプリケーションごとに 1 つしか登録する必要はありません (ウィンドウごとに 1 つではありません)。つまり、オブザーバの実装はオーバーレイではなく XPCOM コンポーネントに置くべきです。
[編集] まとめ
基本的には大体こんな感じです。しかし、あなたに役立つように、httpRequestObserver オブジェクトの少し違ったバージョンも示しておきます。
前に示したバージョンは学習のためには有効ですが、実際のアプリケーションでは次のようなコードにしたほうがいいでしょう。
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
httpChannel.setRequestHeader("X-Hello", "World", false);
}
},
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");
}
};
このオブジェクトには register() と unregister() という便利なメソッドがあり、下のように呼び出すだけでオブザーバを有効にする事が出来ます。
httpRequestObserver.register();
また、終了時にはオブザーバの登録を解除するのも忘れないでください。
httpRequestObserver.unregister();
以上です。
[編集] サンプルコード
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 == "app-startup") {
LOG("----------------------------> app-startup");
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;
}
カテゴリ: Extensions | HTTP | XULRunner