这是什么bug???
发布于 11 年前 作者 networkwx 4688 次浏览 最后一次编辑是 8 年前

我想通过domain把截获的错误返回给客户端(下面的实现是模拟一个异步异常),第一次请求没有问题,但是第二次以后浏览器都会一直处于pending状态,我的理解是第二次请求使用了第一次请求domain里面的对像,也就是说B域访问了A域下面的变量,这样跨域访问数据导致第二次以后的请求拿到的response对像都是A域这个上下文中的,而第一次请求后response已经无效了,也就是说A域这个response没用了,每次都调用response.writeHead都是无效的。当一个进程中有公共变量的时候就会出现这样的问题,求解大神解决这个问题!!

var http = require('http'),
	events = require('events');
	domain = require('domain'),
	net = require('net'),
	util = require('util'),
	shareObject = null;

function InheritEventObject()
{
	events.EventEmitter.apply(this);
}
util.inherits(InheritEventObject, events.EventEmitter);

var cnt = 0;
http.createServer(function(request, response) {
	var rdomain = domain.create();
	rdomain.data = ++cnt;
	rdomain.on('error', function(err) {
		console.log(this.data);//每次都是1
		response.writeHead(500);
		response.end(err.stack);
	});
	rdomain.run(function(){
		var obj = getShareObject();
		obj.emit("throwError");
	});
}).listen(8080);

function getShareObject()
{
	if(shareObject === null)
	{
		shareObject = new InheritEventObject();
		shareObject.on("throwError", function(){
			throw new Error("hello error");
		});
	}
	return shareObject;
}
5 回复

改为setHeader吧,write只能写一次

在rdomain的error里面,每次拿到的response都是第一次的。setHeader也没用。

function InheritEventObject()
{
    // 删掉下面这一行就正常了,暂时没看是神马原因
    // 但有一点可以肯定的是,你这种写法跟后面的util.inherits()是重复的
    // events.EventEmitter.apply(this);
}
util.inherits(InheritEventObject, events.EventEmitter);

大概的原因是: 本来你想实现继承EventEmitter,直接执行util.inherits(InheritEventObject, events.EventEmitter);即可,但是你又在InheritEventObject()中执行了events.EventEmitter.apply(this);,导致把当前的Domain对象绑定到了新创建的InheritEventObject对象上(其实你这种写法本来就是不对的)。以后在每次访问请求时,用的是同一个InheritEventObject对象,那么其出错的时候,也是触发同一个Domain对象的error事件,而里面的Response对象早已经关闭了,所以只要第一次请求能返回,后续的请求都没法返回出错信息。

而若在rdomain.on('error', function () {})处理后,执行rdomain.dispose()来销毁当前的Domain对象,则原来的InheritEventObject对象所绑定的Domain也失效,程序能正确找到当前真正的Domain,所以能正常运行:

 rdomain.on('error', function(err) {
        console.log(this.data);//每次都是1
        response.writeHead(500);
        response.end(err.stack);
        rdomain.dispose();
    });

EventEmitter的源码:

function EventEmitter() {
  this.domain = null;
  if (exports.usingDomains) {
    // if there is an active domain, then attach to it.
    domain = domain || require('domain');
    if (domain.active && !(this instanceof domain.Domain)) {
      this.domain = domain.active;
    }
  }
  this._events = this._events || null;
  this._maxListeners = this._maxListeners || defaultMaxListeners;
}

@leizongmin nice…感谢。。

回到顶部