nsITraceableChannel 编辑

netwerk/base/public/nsITraceableChannel.idlScriptable This interface is used to allow intercepting of HTTP traffic. It is implemented by nsIHttpChannel. 1.0 66 Introduced Gecko 1.9.0.4 Inherits from: nsISupports Last changed in Gecko 1.9.0.4

The typical way to use this interface is as follows:

After that your nsIStreamListener implementation will get the response data and will be able to pass the data on to the original nsIStreamListener (possibly modifying it).

See nsITraceableChannel, Intercept HTTP Traffic for a more detailed description with code samples.

See Modify URL before loading page in firefox for an overview of how to modify a request before it is made.

Method overview

nsIStreamListener setNewListener(in nsIStreamListener aListener);

Methods

setNewListener()

Replaces the channel's current listener with a new one, returning the listener previously assigned to the channel.

nsIStreamListener setNewListener(
  in nsIStreamListener aListener
);
Parameters
aListener
An nsIStreamListener to be notified of events on the HTTP channel.
Return value

The previous listener for the channel. Each listener call through to the previous listener for every call, in order to establish a call chain to allow all interested parties a chance to act on each event.

Implementing nsIStreamListener

The nsIStreamListener passed to setNewListener() should implement the following methods, which are called to notify it of events that occur on the HTTP stream:

  • onStartRequest: An HTTP request is beginning.
  • onDataAvailable: Data is arriving on the HTTP channel.
  • onStopRequest: The HTTP request is ending.
Note: It is critical that you pass along requests to the previous listener as soon as possible -- especially for onStartRequest.

Channels may restrict when you may replace the listener. In particular, listeners typically should not be replaced after onStartRequest has been called.

Example

This example can be copied and pasted into a JavaScript interpreter and run. This example uses Promise syntax that is available in Firefox 30 and onwards.

/////// START - DO NOT EDIT
var {classes: Cc, interfaces: Ci, results: Cr, Constructor: CC, utils: Cu} = Components;
Cu.import('resource://gre/modules/Services.jsm');

var BinaryInputStream = CC('@mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream');
var BinaryOutputStream = CC('@mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream');
var StorageStream = CC('@mozilla.org/storagestream;1', 'nsIStorageStream', 'init');

function TracingListener() {
	this.receivedChunks = []; // array for incoming data. holds chunks as they come, onStopRequest we join these junks to get the full source
	this.responseBody; // we'll set this to the
	this.responseStatusCode;

	this.deferredDone = {
		promise: null,
		resolve: null,
		reject: null
	};
	this.deferredDone.promise = new Promise(function(resolve, reject) {
		this.resolve = resolve;
		this.reject = reject;
	}.bind(this.deferredDone));
	Object.freeze(this.deferredDone);
	this.promiseDone = this.deferredDone.promise;
}
TracingListener.prototype = {
	onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
		var iStream = new BinaryInputStream(aInputStream) // binaryaInputStream
		var sStream = new StorageStream(8192, aCount, null); // storageStream // not sure why its 8192 but thats how eveyrone is doing it, we should ask why
		var oStream = new BinaryOutputStream(sStream.getOutputStream(0)); // binaryOutputStream

		// Copy received data as they come.
		var data = iStream.readBytes(aCount);
		this.receivedChunks.push(data);

		oStream.writeBytes(data, aCount);

		this.originalListener.onDataAvailable(aRequest, aContext, sStream.newInputStream(0), aOffset, aCount);
	},
	onStartRequest: function(aRequest, aContext) {
		this.originalListener.onStartRequest(aRequest, aContext);
	},
	onStopRequest: function(aRequest, aContext, aStatusCode) {
		this.responseBody = this.receivedChunks.join("");
		delete this.receivedChunks;
		this.responseStatus = aStatusCode;
		this.originalListener.onStopRequest(aRequest, aContext, aStatusCode);

		this.deferredDone.resolve();
	},
	QueryInterface: function(aIID) {
		if (aIID.equals(Ci.nsIStreamListener) || aIID.equals(Ci.nsISupports)) {
			return this;
		}
		throw Cr.NS_NOINTERFACE;
	}
};

var httpResponseObserver = {
	observe: function(aSubject, aTopic, aData) {
		var newListener = new TracingListener();
		aSubject.QueryInterface(Ci.nsITraceableChannel);
		newListener.originalListener = aSubject.setNewListener(newListener);
/////// END - DO NOT EDIT
		newListener.promiseDone.then(
			function() {
				// no error happened
				console.log('yay response done:', newListener.responseBody);
			},
			function(aReason) {
				// promise was rejected, right now i didnt set up rejection, but i should listen to on abort or bade status code then reject maybe
			}
		).catch(
			function(aCatch) {
				console.error('something went wrong, a typo by dev probably:', aCatch);
			}
		);
	}
};

Services.obs.addObserver(httpResponseObserver, 'http-on-examine-response', false);
// Services.obs.removeObserver(httpResponseObserver, 'http-on-examine-response'); // call this when you dont want to listen anymore

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

词条统计

浏览:38 次

字数:8568

最后编辑:7年前

编辑次数:0 次

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文