函数中如何区分不同的请求
发布于 7 年前 作者 lyt308012546 3437 次浏览 来自 问答

如何在函数中不传参数request的情况下,区分每一条请求? 我写两个log是因为要告知调用者的层数是未知的。

function log1(msg) {
    let id = ?
     console.log(id + '发送了消息:' + msg);
}
function log(msg) {
  	log1(msg)
}
router.get('*', () => {
    log('abc');
});

这是一个web后端代码,因为node的单线程问题,所以不能写全局变量, 因为并发请求会更改全局变量导致混乱,我现在感觉没办法实现。 所以看大家有没有想法,我一开始想从caller中获取,也没成功。

=====================================================================================

我觉得问题没有描述清楚,所以写一下具体碰到的情况。

我在使用log4js记录日志,log4js提供了这样一个方法可以自定义token,那么就需要有一个获取当前用户的方法,或者获取当前请求的方法,这个获取当前请求如何获取。

log4js.configure({
  appenders: {
    out: { type: 'stdout', layout: {
      type: 'pattern',
      pattern: '%d %p %c %x{user} %m%n',
      tokens: {
        user: function(logEvent) {
          return AuthLibrary.currentUser();
        }
      }
    }}
  },
  categories: { default: { appenders: ['out'], level: 'info' } }
});
const logger = log4js.getLogger();
logger.info('doing something.');
15 回复

router.get(’*’, (res) => { log(‘abc’); });

res 这个参数就可以区分了吧。如果想要确定具体哪个人的请求,可以在request.header里添加token什么的来确定。

@xiaotuni 就是不能传请求过去,如果传请求过去肯定能区分了,问题是不可以传请求过去。

@lyt308012546 不传递参数过去怎么区分…

log方法里,不能加参数吗?

@DevinXian 这就是问题啊,因为node单线程,所以不能用全局变量,很头疼。

你必须为不同的客户端创建新实例,你想要解决的问题,应该是数据库连接等。你可以在 Express 中间件通过 res 或者 req 来绑定这个实例,从而在所有的 路由中能够继续使用它们。如果是要做聊天应用,请使用 socket.io ,它为每一个客户端都设置了独立的 socket id,因此可以使用它来标识不同的连接。

那就用队列吧。将要log的信息放到队列里。

const logList = [];
let isCallLog = false;
router.get("*",(req,res)=>{
    // 这里可以把要数据存放到一个 list里。
	logList.push({id:123,...});
	BeginCallLog();
});
function BeginCallLog(){
    if(isCallLog){
	  return;
	}
	CallLog();
}

function CallLog() {
    const item = logList.shift();
	if(item){
	   isCallLog  = true;
	   log(item.fields);
	   CallLog(); // 自己调用自己处理下一条数据。
	}
	isCallLog = false;
}

大概这样吧。

@Hyurl 我再次更新描述了我的问题,可以看到我使用的是log4js,是没有可以让我传入任何ID的参数的,需要从全局调用一个方法获取当前请求。

@xiaotuni Calllog如何在并发的情况下知道是哪个请求打印的日志呢?

@lyt308012546 那这个无法知道是哪个请求,因为 nodejs 是单线程的,全局变量或者静态对象都是共用的,要区分开来,必须为请求创建不同的实例。 不过,你说的没有传图任何 ID 参数,其实也不对,你可以自己传参数过去。你可以全局使用 session 或者 token 之类的方式,来代替 socket ID,然后在记录日志时通过前缀的方式区分它们。

目测只能通过传参数了,不过log代码可以写优雅一些,比如放在中间件中,防止代码中到处都是log。对于部分log实在要放在业务代码里,就通过参数一层层传把。

@lyt308012546 logList.push() 这里面存放一个对象,可以存放当前tokeId ,sessionID,用户ID等,然后再把要输出的数据存放里面。

logLog.push({id:‘11111’, msg:‘message info’});

只往这里插入,在callLog() 方法里,一个一个取 const item = logList.shift() 。在这里 item 里存放了你的ID标识。

const item = logList.shift() ;
const { id, msg } = item;
log(id + msg);          // 就可以取分是哪个请求了呀。。

@xiaotuni 不好意思,看到了,不过你还是通过参数把id传进去了,我说不传ID是有原因的,我举个例子你可能明白。

const logList = [];
let isCallLog = false;
router.get("*",(req,res)=>{
    // 这里可以把要数据存放到一个 list里。
	let id=123;
	bar(id);
	BeginCallLog();
});

function bar(id){
	fun(id)
}

function fun(id){
	foo(id);
}

function foo(id){
	logList.push({id:id,...});
}
function BeginCallLog(){
    if(isCallLog){
	  return;
	}
	CallLog();
}

function CallLog() {
    const item = logList.shift();
	if(item){
	   isCallLog  = true;
	   log(item.fields);
	   CallLog(); // 自己调用自己处理下一条数据。
	}
	isCallLog = false;
}

@nqdy666 我目前能想到的也是这样了,业务代码打log,其他的抛出错误或异常就可以了。

回到顶部