使用nodejs创建一个http服务器是非常简单的。突然想到同学的一句话,“经济基础决定上层建筑”。这句话似乎是个万金油,在任何事情上都可以评论一二。所以这种简单其实是因为nodejs在内部帮我们封装了很多,隐藏了非常多的细节。本文旨在深入到这些细节,拨开这个面纱。
为了行文方便,每段代码都加了标志CS。
开始
CS1
var http = require('http');
http.createServer(function(req, res) {
res.end('ok');
}).listen(3000);
创建一个http服务器就这么简单。http模块是nodejs内置的模块。这段代码执行了两个函数,分别是http.createServer
和.listen
。那么问题来了。
- 问题1:req/res是从哪里来的
- 问题2:相应头部信息是如何创建的
- 问题3:listen函数发生了什么
带着这些问题来看源码到底发生了什么。我看的源码是https://github.com/nodejs/node/tree/master/lib。
createServer
CS2
/lib/http.js
const server = require('_http_server');
const Server = server.Server;
const ClientRequest = client.ClientRequest;
function createServer(requestListener) {
return new Server(requestListener);
}
这里的requestListener
就是我们代码中传入的回调函数。
function(req, res) {
res.end('ok');
}
createServer
函数返回的是Server
的一个实例。所以需要到_http_server
文件中去找Server
这个构造函数。
CS3
/lib/_http_server.js
function Server(requestListener) {
if (!(this instanceof Server)) return new Server(requestListener);
net.Server.call(this, { allowHalfOpen: true });
if (requestListener) {
this.on('request', requestListener);
}
// ...
this.on('connection', connectionListener);
// ...
}
util.inherits(Server, net.Server);
可以看到,Server
借用了net.Server
的构造函数。这是由于Server
继承自net.Server
。后者的构造函数设置了一些属性并继承自EventEmitter
。所以可以使用emit
/on
等。另外,从nodejs官方文档看到net.Server
可以创建一个TCP或者IPC服务器。
在Server
构造函数中设置了request
和connection
事件的回调函数(重要)。不要忘了requestListener
哦,这是我们在createServer
中设置的回调。然后还有个connectionListener
。这是触发connection
事件时的回调。
- 问题4:什么时候触发connection事件
CS4
/lib/_http_server.js
function connectionListener(socket) {
debug('SERVER new http connection');
httpSocketSetup(socket);
// ...
var parser = parsers.alloc();
parser.reinitialize(HTTPParser.REQUEST);
parser.socket = socket;
socket.parser = parser;
parser.incoming = null;
var state = {
// ...
};
parser.onIncoming = parserOnIncoming.bind(undefined, this, socket, state);
parser[kOnExecute] =
onParserExecute.bind(undefined, this, socket, parser, state);
// ...
}
这里需要关注的是parser
这个对象和parserOnIncoming
函数。后者使用了bind
,并预先传入了三个参数(parser, socket, state)
。parser来自于parsers.alloc()。parser