这是一个坑爹的Nodejs问题,高手请解释
这是一个坑爹的Nodejs问题,高手请解释
var connect = require(‘connect’); var app = connect(); app.use(connect.logger(‘dev’)); app.use(connect.cookieParser(‘dd’)); app.use(connect.session({secret:‘123’})); app.use(function(req,res,next){ if(req.session.pv){ res.writeHeader(‘200’,{‘Content-type’:‘text/html’}); res.write('views: ’ + req.session.pv); res.end(); req.session.pv ++; }else{ req.session.pv = 1; res.end(‘Refresh’); }
}) app.listen(3000);
这是一个很坑爹的问题,req.session.pv每一次都是双数,如:2,4,6,8但是req.session.pv只是每次自加1而已
这个问题确实比较坑爹,涉及到的是Node.js中的异步处理机制。让我们一步一步来分析。
问题描述
代码的目标是创建一个简单的Web服务器,记录用户访问页面的次数。每次用户刷新页面时,req.session.pv
会增加1,并且将当前的访问次数显示给用户。
问题所在
问题是,req.session.pv
总是显示为偶数(例如2, 4, 6, 8),而不是每次递增1。这显然是不对的,因为根据代码逻辑,req.session.pv
应该每次只递增1。
原因分析
问题出在res.write()
和 res.end()
的调用顺序上。由于Node.js的异步特性,当res.writeHeader()
和res.write()
被调用时,req.session.pv ++
可能还没有执行。因此,下一次请求可能会读取到旧的值,导致看起来像是每次增加了2而不是1。
解决方案
正确的做法是在发送响应之前完成所有必要的操作。具体来说,我们可以在更新req.session.pv
之后再发送响应。以下是修改后的代码:
var connect = require('connect');
var app = connect();
app.use(connect.logger('dev'));
app.use(connect.cookieParser('dd'));
app.use(connect.session({ secret: '123' }));
app.use(function(req, res, next) {
if (req.session.pv) {
req.session.pv++;
} else {
req.session.pv = 1;
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('views: ' + req.session.pv);
res.end();
});
app.listen(3000);
console.log('Server running at http://localhost:3000/');
关键点
- 异步处理:Node.js 是事件驱动的,所有的I/O操作都是非阻塞的。这意味着你需要确保在发送响应之前完成所有必要的操作。
- 更新session变量:确保在更新
req.session.pv
之后再进行响应的发送。 - 避免重复写入:使用
res.writeHead()
、res.write()
和res.end()
来确保响应头和响应体正确发送。
通过这种方式,可以确保每次请求时req.session.pv
都正确递增1。
估计你测试的时候浏览器的每次请求都另带一个favoricon的请求。
+1 把 req.url 打印出来就清楚了。
这个问题确实有点坑爹。问题出在 res.write
和 res.end
的使用上。res.write
是用来写入响应体的一部分,而 res.end
则是结束响应并发送给客户端。如果你在同一个响应中同时使用了 res.write
和 res.end
,那么 Node.js 会认为这是两个独立的响应部分。
在你的代码中,res.write
和 res.end
被分开调用,这会导致请求处理逻辑没有按预期执行。具体来说,每次请求时,res.end
会先于 req.session.pv++
执行,导致计数器没有正确递增。
你可以将 res.write
和 res.end
合并为一个语句来修复这个问题,或者使用 res.end
的可选参数来传递响应体内容。
下面是修改后的代码示例:
var connect = require('connect');
var app = connect();
app.use(connect.logger('dev'));
app.use(connect.cookieParser('dd'));
app.use(connect.session({ secret: '123' }));
app.use(function(req, res, next) {
if (req.session.pv) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('views: ' + req.session.pv++);
} else {
req.session.pv = 1;
res.end('Refresh');
}
});
app.listen(3000);
在这个修改后的代码中,我们使用了 res.end
的可选参数来传递响应体内容,并且把 req.session.pv++
放在 res.end
前面,这样可以确保每次请求时 req.session.pv
都能正确递增。