http server源码解析

}

// lib/_http_server.js

function Server(options, requestListener) {

if (typeof options === ‘function’) {

requestListener = options;

options = {};

}

// …

if (requestListener) {

// 当req和res对象都生成好以后,就会触发request事件,让业务函数对请求进行处理

this.on(‘request’, requestListener);

}

// connection事件可以在net Server类中看到,当三次握手完成后,就会触发这个事件

this.on(‘connection’, connectionListener);

}

ObjectSetPrototypeOf(Server.prototype, net.Server.prototype);

ObjectSetPrototypeOf(Server, net.Server);

function connectionListener(socket) {

// 这里就是执行connectionListenerInternal函数并传入this和socket参数

defaultTriggerAsyncIdScope(

getOrSetAsyncId(socket), connectionListenerInternal, this, socket

);

}

// connection事件触发后的回调函数,这个函数将在“解析生成req、res对象”板块进行讲解

function connectionListenerInternal(server, socket) {

// …

}

调用 http.createServer 函数时,会返回一个 Server 实例, Server 是从 net Server 类继承而来的。因此, http Server 实例也就具备监听端口生成服务,与客户端通信的能力。前面例子中调用的 listen 函数,实际上就是 net Server 中的 listen 。

在实例 Server 对象的过程中,会分别监听 request 和 connection 这两个事件。

  • connection :这里监听的就是 net 中的 connection 事件,当客户端发起请求,TCP三次握手连接成功时,服务端就会触发 connection 事件。 connection 事件的回调函数 connectionListenerInternal 将在下一个板块进行讲解。

  • request :当 req 和 res 对象都初始成功以后,就会发布 request 事件,前面代码中我们可以看到 request 事件的回调函数 requestListener 就是开发者调用http.createServer 时传入的回调函数,这个回调函数会接收 req 和 res 两个对象。

生成req、res对象

===========

当客户端TCP请求与服务端连接成功后,服务端就会触发 connection 事件,此时就会实例一个 http-parser 用来解析客户端请求,当客户端数据解析成功后,就会生成一个 req 对象,接下来我们先来看下 req 对象生成过程。

// lib/_http_server.js

function Server(options, requestListener) {

// …

// 客户端与服务端三次握手完成,触发connection事件

this.on(‘connection’, connectionListener);

}

function connectionListener(socket) {

// 这里就是执行connectionListenerInternal函数并传入this和socket参数

defaultTriggerAsyncIdScope(

getOrSetAsyncId(socket), connectionListenerInternal, this, socket

);

}

/**

  • @param {http Server} server

  • @param {net Socket} socket

*/

function connectionListenerInternal(server, socket) {

// …

// parsers.alloc函数执行会使用返回一个free list分配的HTTPParser对象

const parser = parsers.alloc();

// 请求解析器初始化工作

parser.initialize(

HTTPParser.REQUEST,

new HTTPServerAsyncResource(‘HTTPINCOMINGMESSAGE’, socket),

server.maxHeaderSize || 0,

server.insecureHTTPParser === undefined ?

isLenient() : server.insecureHTTPParser,

server.headersTimeout || 0,

);

parser.socket = socket;

socket.parser = parser;

// …

}

// lib/_http_common.js

const parsers = new FreeList(‘parsers’, 1000, function parsersCb() {

// 这里使用http-parser库来作为请求解析器

const parser = new HTTPParser();

cleanParser(parser);

// …

return parser;

});

http Server 中使用 http-parser 实例来作为客户端请求的解析器。值得注意的是,这里使用了 free list 数据结构来分配 parser 对象。

// lib/internal/freelist.js

class FreeList {

constructor(name, max, ctor) {

this.name = name;

this.ctor = ctor;

this.max = max;

this.list = [];

}

// 需要对象,分配一个对象

alloc() {

return this.list.length > 0 ?

this.list.pop() :

// 这里的ctor是实例FreeList对象时,传入的统一新增对象的方法

ReflectApply(this.ctor, this, arguments);

}

// 对象用完,释放对象

free(obj) {

if (this.list.length < this.max) {

this.list.push(obj);

return true;

}

return false;

}

}

这部分运用到 free list 数据结构。使用该数据结构目的是减少对象新建销毁所带来的性能消耗,它会维护一个长度固定的队列,队列中的所有对象大小都相同。当需要使用对象的时候,会优先从队列中获取空闲的对象,如果队列中已经没有可用的对象,就会新建一个与队列中存放的对象大小相同的对象,供程序使用。对象使用完后,不会直接销毁,而是会将对象压入队列中,直到后面被推出使用。

了解 free list 后,我们继续来看下客户端请求的解析。

// lib/_http_common.js

const parsers = new FreeList(‘parsers’, 1000, function parsersCb() {

const parser = new HTTPParser();

cleanParser(parser);

// 为这些事件绑定回调函数

parser[kOnHeaders] = parserOnHeaders;

parser[kOnHeadersComplete] = parserOnHeadersComplete;

parser[kOnBody] = parserOnBody;

parser[kOnMessageComplete] = parserOnMessageComplete;

return parser;

});

http-parser 在解析客户端请求也是基于事件来对数据进行处理:

kOnHeaders

kOnHeadersComplete

kOnBody

kOnMessageComplete

TCP在进行数据传输的过程中,会将超出缓冲区剩余空间大小的数据进行拆包,使得同一个请求数据包可能分多次发送给服务端。这里 kOnHeaders 和 kOnBody 就是用于拼接被拆分的数据,组合同一个请求的数据。

当请求头解析完成以后,会执行 kOnHeadersComplete 回调函数,在这个回调函数中会生成 req 对象。

// lib/_http_common.js

const { IncomingMessage } = require(‘_http_incoming’);

// 请求头解析完成后执行的回调函数

function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, url, statusCode, statusMessage, upgrade, shouldKeepAlive) {

const parser = this;

const { socket } = parser;

// …

// 绝大多数情况下socket.server[kIncomingMessage]等于IncomingMessage

const ParserIncomingMessage = (socket && socket.server && socket.server[kIncomingMessage]) || IncomingMessage;

const incoming = parser.incoming = new ParserIncomingMessage(socket);

// …

return parser.onIncoming(incoming, shouldKeepAlive);

}

// lib/_http_incoming.js

function IncomingMessage(socket) {

// …

}

kOnHeadersComplete 回调中实例出来的 IncomingMessage 对象就是 req 对象。回调最后会执行 parser.o 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 nIncoming 函数,生成 res 对象。

// lib/_http_server.js

function connectionListenerInternal(server, socket) {

// …

// 这个就是kOnHeadersComplete回调最后执行的函数

parser.onIncoming = FunctionPrototypeBind(parserOnIncoming, undefined, server, socket, state);

// …

}

// 第四个参数就是req对象,req对象是在parser.onIncoming(incoming, shouldKeepAlive)函数执行的时候传入的incoming对象

function parserOnIncoming(server, socket, state, req, keepAlive) {

// …

ArrayPrototypePush(state.incoming, req);

// 实例res对象

const res = new serverkServerResponse;

if (socket._httpMessage) {

ArrayPrototypePush(state.outgoing, res);

}

// …

// 这个事件会在调用res.end的时候触发

res.on(‘finish’, FunctionPrototypeBind(resOnFinish, undefined, req, res, socket, state, server));

// …

server.emit(‘request’, req, res); // 发布request事件,执行createServer函数调用传入的业务处理函数

// …

}

// 这里的ServerResponse继承于OutgoingMessage类,后续将会介绍到

this[kServerResponse] = options.ServerResponse || ServerResponse;

当 req 和 res 对象都初始成功并存放后,就会执行createServer函数调用传入的业务处理函数。

当 req 生成后,便会执行 parserOnIncoming 生成 res 对象,同时会在 res 对象中注册finish 事件,当业务代码执行 res.end 的时候,就会触发这个事件。当 req 和 res 对象都准备好后,就会发布 request 事件,同时将 req 和 res 对象传入。 request 事件的回调函数就是业务代码调用 http.createServer 时传入的回调函数。

res.end执行

=========

const http = require(‘http’);

http.createServer((req, res) => {

res.end(‘hello word’);

}).listen(8080);

当业务处理完成后,业务代码中主动调用 res.end() 函数,响应客户端请求,接下来我们看下。

// lib/_http_server.js

function ServerResponse(req) {

FunctionPrototypeCall(OutgoingMessage, this);

// …

}

ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);

ObjectSetPrototypeOf(ServerResponse, OutgoingMessage);

ServerResponse 类是从 OutgoingMessage 类继承的。业务中使用的 res.end 方法也是在 OutgoingMessage 中进行定义的,下面我们看下 OutgoingMessage 类实现。

// lib/_http_outgoing.js

function OutgoingMessage() {

// …

this._header = null;

// …

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值