why request event is fired before data event in http modlues of node.js.

来源:互联网 发布:广州java语言培训机构 编辑:程序博客网 时间:2024/06/06 19:04

if we create a http server normally, the code appearance is like that:


"use strict";let http=require('http');let ser=http.createServer().listen(80);ser.on('connection',(s)=>{    let co=1;    s.on('data',(data)=>{        console.log('data\n');    })    ser.once('request',(req,res)=>{ //ser object isn't change.        console.log('req');         //if we use the on instead of once,        res.end('123');             // every connection emitted we will bind a request event.    })});

if we write some code to visit the server, we can get some Incredible things.
like this:

"use strict";let net=require('net');let fs = require('fs');let socket=new net.Socket();let opt={    host:'127.0.0.1',    port:80}socket.connect(opt,()=>{    socket.on('data',(data)=>{        console.log(data.toString());        socket.end();    });    socket.on('error',(e)=>{        console.log(e)    });    socket.on('end',(e)=>{        console.log('end')    });    let html=fs.readFileSync('./a.txt');    socket.write(html);});

Running the server code firstly and running the request code secondly, we inspect the result from console.
It show that
req

data


The result is 'req' first and 'data' in back of that Unexpectedly.
Why?
The result should be "data req",isn't it?


Preciously, I deemed we must get data that be obtained from data event emitted before produce req object.
The Process is about this:
After getting data, we can produce the req object through combining the data parsed and part of socket that is a read stream.
So, it obviously and affirmatively show request event is later emitted than data event.

But the result confused me.
why it can appear the phenomenon.

I perplexity find the source of http module of node.js.
we should start from the function named createServer;

:( In fact,he do nothing.

const Server = exports.Server = server.Server;exports.createServer = function(requestListener) {  return new Server(requestListener);};



we continue to find the object server;
the declare of server:
const server = require('_http_server');

unfortunately, we must turn to _http_server module.

function Server(requestListener) {  if (!(this instanceof Server)) return new Server(requestListener);  net.Server.call(this, { allowHalfOpen: true });  if (requestListener) {    this.addListener('request', requestListener);  }  /* eslint-disable max-len */  // Similar option to this. Too lazy to write my own docs.  // http://www.squid-cache.org/Doc/config/half_closed_clients/  // http://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F  /* eslint-enable max-len */  this.httpAllowHalfOpen = false;  this.addListener('connection', connectionListener);  this.timeout = 2 * 60 * 1000;  this._pendingResponseData = 0;}util.inherits(Server, net.Server);

the function tell us the http server is inherited to net.Server.

Now, we find there is no function to be invoked, but there is a event--connection.
Following the clues, we find a connectionListener function.

It too large to be read. :( 261~548
function connectionListener(socket){...}
It seems like connection events listener of net.server.

To fire the request event, It must exit emit('request',req,res);
so, we can find that for a start;
column 528~533

if (self.listenerCount('checkContinue') > 0) {  self.emit('checkContinue', req, res);} else {  res.writeContinue();  self.emit('request', req, res);}

the structure of function:
267~295 the declare of function
296~353 statements
354~459 the callback of socket
460~547 function

it belongs to function 460~547 function parserOnIncoming(req, shouldKeepAlive){..}
According to the function name, we can know the function will be invoked in the Incoming of parser.
what's Parser?
search the key of parse-->
we find
316 var parser = parsers.alloc();
332 parser.onIncoming = parserOnIncoming;
363~369

function socketOnData(d) {  assert(!socket._paused);  debug('SERVER socketOnData %d', d.length);  var ret = parser.execute(d);  onParserExecuteCommon(ret, d);}

we find the column 334-->socket.on('data', socketOnData);

the function of parser.execute is in socketOndata,It is very reasonable.
so I can infer like that:

"use strict"let event=require('events').EventEmitter;let un=require('util');function a(){}un.inherits(a,event);let c=new a();c.on('data',()=>{console.log(`1 data`);c.emit('request');});c.on('data',()=>{console.log(`2,data`);});c.on('request',()=>{<span style="white-space:pre"></span>console.log(`1 request`);});c.emit('data');

the result is:
1 data
1 request
2,data

I test many times, the result is stable.

but when parserOnIncoming will be invoked actually?
we find the parsers is from _http_common module.

we find 'parser.onIncoming(parser.incoming, shouldKeepAlive);'' in function parserOnHeadersComplete.
and  when parserOnHeadersComplete will be invoked?
we just find parser[kOnHeadersComplete] = parserOnHeadersComplete;
because the HTTPParser is written in c we can't read, 
so we only can infer from function name that it will be invoked amid the process of parse happened.
and the parser will be execute in the callback of data event to socket.

the origin of req object is come from one of parameter of  function parserOnIncoming.
In that we find the statement-
'skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive);'
'  parser.incoming = new IncomingMessage(parser.socket);'

so the req object is a instance of IncomingMessage;

0 0
原创粉丝点击