1. 程式人生 > >node.js——http原始碼解讀

node.js——http原始碼解讀

從慕課網上看到相關node視訊,裡面對http原始碼分析過程做了詳細介紹,其思路和方法很適合於檢視其它原始碼,故記錄下來 以搭建一個web伺服器為栗子
var http = require('http');

http.createServer( function(request ,response){
      response.writeHead( 200,{'Content-Type' :'text/plain'});
      response.end( 'Hello World\n');
}).listen(1337, '127.0.0.1');

console.log('Server running at http://127.0.0.1:1337/' );

問題: 1、createServer()做了什麼事情 2、回撥函式何時被呼叫 3、request和response是什麼
4、listen()做了哪些事 一、createServer()
<strong>http.js</strong>

exports.createServer = function(requestListener) {
return new Server(requestListener); //返回server例項,將回調函式做為引數傳入,exports將介面暴露出去
};

>>server

const server = require('_http_server');//引入_http_server私有模組

進入_http_server.js >>Server()
<strong>_http_server.js</strong>

function Server(requestListener) {
  >>>>>>>
  if (requestListener) {
    this.addListener('request', requestListener);//如果有回撥函式,對當前例項上新增事件監聽,監聽request,若有request事件觸發,則呼叫回撥         
  }
  <<<<<<
}
request(以下簡稱req)事件何時觸發?(直接在當前目錄下搜尋關鍵字 "emit('request'")【EventEmitter傳送和接收事件
<strong>_http_server.js</strong>

function parserOnIncoming(req, shouldKeepAlive) {
  >>>>>>
  var res = new ServerResponse(req);

  self.emit('request',req,res);//呼叫emit方法將request事件傳送給每一個監聽器的例項並傳入req&res,即栗子中回撥函式裡接收的兩個引數
  <<<<<<
}
那麼req和res如何生成? 首先在當前函式下>>req發現以作為引數傳入,所以不會再當前函式下新構建 >>res,發現為ServerResponse()的例項並傳入req >>ServerResponse
<strong>_http_server.js</strong>

function ServerResponse(req) {
  >>>>>
  util.inherits(ServerResponse, OutgoingMessage);//繼承自OutgoingMessage,為OM的一個子類,所以回撥函式裡的res也是OM的一個例項

  exports.ServerResponse = ServerResponse;//並暴露介面
   <<<<<
}
>>OutgoingMessage
<strong>_http_server.js</strong>

const OutgoingMessage = require('_http_outgoing').OutgoingMessage;//來自_http_outgoing私有模組
<strong>_http_outgoing.js</strong>

function OutgoingMessage() {

Stream.call(this);
>>>>返回一些與伺服器有關的屬性<<<
}

util.inherits(OutgoingMessage, Stream);//繼承自Stream

exports.OutgoingMessage = OutgoingMessage;

到此res線找到,res為ServerMessage的例項,也是OutgoingMessage的例項,以下用圖形演示:


再來看req,在parserOnIncoming()作為引數傳入,>>parserOnIncoming()在哪裡被呼叫

<strong>_http_server.js</strong>

parser.onIncoming = parserOnIncoming;

>>parser
<strong>_http_server.js</strong>

var parser = parsers.alloc();

>>parsers
<strong>_http_server.js</strong>

const common = require('_http_common');
const parsers = common.parsers;

到_http_common模組中>>onIncoming()何時呼叫
<strong>_http_common.js</strong>

skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive);

其中parser.incoming就是傳入的req >>parser.incoming
<strong>_http_common.js</strong>

parser.incoming = new IncomingMessage(parser.socket);//IncomingMessage的例項並將套接字作為引數傳入
>>IncomingMessage
<strong>_http_common.js</strong>

const incoming = require('_http_incoming');
const IncomingMessage = incoming.IncomingMessage;//來自_http_incoming模組


所以req是IncomingMessage的一個例項 至此req線找到,req為IncomingMessage的例項,以下用圖形演示

二、listen():

<strong>_http_server.js
</strong>
const net = require('net');

function Server(){
     net.Server.call(this, { allowHalfOpen: true });
>>>>>
     this.addListener('connection', connectionListener);
<<<<<
}
util.inherits(Server, net.Server);//Server繼承net.Server

function connenctListener(socket){
>>>>
     function parseronIncoming(req,shouldKeepAlive){
          >>>
              將request事件傳送給監聽器
          <<<
     }
<<<<
}
parseronIncoming()在connectionListener()裡定義,connectionListener()在'connection'事件觸發時呼叫,那麼connection事件何時觸發? 在當前目錄下查詢事件,沒有找到,由‘net.Server.call(this, { allowHalfOpen: true });’>>net.Server發現net為ner.js模組 >>net.js >>emit('connection
<strong>net.js</strong>

function onconnection(err, clientHandle) {
     >>>>
     self.emit('connection', socket);     
}
conenction在onconnection()裡觸發 >>onconnenction
<strong>net.js</strong>

Server.prototype._listen2 = function(address, port, addressType, backlog, fd) {
>>>>
     this._handle.onconnection = onconnection;
<<<<<     
}
onconnection在_listen2裡執行 >>_listen2
<strong>net.js</strong>

function listen(self, address, port, addressType, backlog, fd, exclusive) {
>>>>
      self._listen2(address, port, addressType, backlog, fd);
<<<<
}
_listen2在listen裡被呼叫 >>listen
<strong>net.js</strong>

Server.prototype.listen = function() {
>>>
<<<
}
listen在Server原型上,又_http_server繼承自net,所以在示例程式碼裡的http.createServer()例項上有listen()方法 以下用圖形演示



http.createServer()建立了一個Server例項並監聽request,listen()觸發監聽事件並執行回撥函式。