之前总结了http模块的http.Server 以及http.ServerResponse类。现在总结http模块的http.ClientRequest类与http.IncomingMessage类。
http.ClientRequest类
http.ClientRequest类是被动创建的,是在使用http.request()和http.get()方法在客户端向服务器端发起请求(这里的发起请求是指请求信息的创建以及发送等)时创建并返回的类,一般用于在客户端生成请求消息 ,是可写流的子类,将数据写入到请求信息中。http.ClientRequest类有一个response事件,用于监听客户端是否收到服务端的响应。
const http=require('http'); options= { host: 'www.cnblogs.com', port: '80', method: 'GET', path: '/aicanxxx', headers: { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 'Accept-Encoding': 'gzip, deflate, sdch', 'Accept-Language': 'en,zh-CN;q=0.8,zh;q=0.6', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'Host': 'www.cnblogs.com', 'If-Modified-Since': 'Sat, 24 Jun 2017 04:38:48 GMT', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' } }; var req=http.request(options,function (res) { console.log(res.statusCode); console.log(JSON.stringify(res.headers)); res.on('data',function (chunk,'utf8') { console.log(chunk); }); res.on('end',function () { console.log('响应已结束'); }); }); req.on('error',function (err) { console.log(err.message); }); req.write('');//往请求体写入数据 req.end();//完成请求并发送
http.request()方法是用于客户端向服务器端发送请求,options是对访问路径的配置,第二个参数是调用http.request()时给response事件添加的一个监听器,当客户端接收到响应信息后调用该监听器。监听器接收一个参数,res就是服务器端发送过来的响应信息,是http.IncomingMessage类的实例。在调用request()方法时会创建并返回http.ClientRequest类,该类用于处理请求信息,比如请求体内容的写入或者请求信息的发送等。http.ClientRequest类中write()方法是将数据写入请求体,end()方法时发送请求信息。
从这里可以看出,客户端发送的请求req是一个可写流的子类http.ClientRequest类的实例,接收到的响应信息res是一个可读流的子类http.IncomingMessage类的实例。http.IncomingMessage类
http.IncomingMessage类也是被动创建的,是由http.Server类和http.ClientRequest类创建的,并分别作为第一个参数传递给request事件和response事件的监听器,它是一个可读流的子类。以下方法会创建该类:
var server = http.createServer(function(request,response){ ... }); var request = http.request(options, function(response) { ... });
除此之外,会创建http.Server类和http.ClientRequest类的实例的程序都会创建该类。http.IncomingMessage类继承了了‘data’事件,‘end’事件,定义了‘close’事件,比如在客户端收到服务端的响应时,会调用response监听器,而监听接收的参数res就是http.IncomingMessage的实例,可以绑定data事件的监听器对数据进行操作,在数据接收完成之后可以调用end事件监听器等。
const http=require('http'); options= { host: 'www.cnblogs.com', port: '80', method: 'GET', path: '/aicanxxx', }; var req=http.request(options,function (res) { console.log(res.statusCode); console.log(JSON.stringify(res.headers)); res.on('data',function (chunk,'utf8') { console.log(chunk); }); res.on('end',function () { console.log('响应已结束'); }); }); req.write('');//往请求体写入数据 req.end();//完成请求并发送
这里的req是http.ClientRequest的实例,表示请求信息。
请求信息与响应信息
这里需要注意的是服务器端的响应信息res_server与客户端接收的响应信息res_client是不相同的,res_server是http.ServerResponse类生成的,是该类的实例,是可写的;而res_client是IncomingMessage的实例,是可读的。由于官方文档中说过http.IncomingMessage类是由http.Server类和http.ClientRequest类创建的,可以将这种变化看成暗盒,不需要深入了解,故可以看成是服务器在发送响应请求时将响应信息由http.ServerResponse类的实例经过某种变化转换成了http.IncomingMessage类的实例,完成了可写到可读的变化,方便传输。
同理,服务器端接收到的请求信息req_server与客户端发送的请求信息req_client是不相同的,req_client是由客户端的类http.ClientRequest类产生的,是该类的实例,可以由以下代码证明:console.log(req instanceof http.IncomingMessage);//false console.log(req instanceof http.ClientRequest);//true
req是http.ClientRequest类的实例,故也可以看成是客户端在发送请求时将请求信息由http.ClientRequest类的实例经过某种变化转换成了http.IncomingMessage类的实例,完成了可写到可读的变化。具体流程如下:
总结
http模块的Server、ClientRequest、IncomingMessage、ServerResponse类之间通过监听事件request、response、connection等完美的解决了客户端与服务端的请求和响应问题,客户端通过http.ClientRequest类创建并发送请求信息,通过response事件监听响应信息并对其进行处理;服务端通过http.Server创建服务器,监听request事件获取请求信息,并通过http.ServerResponse创建并发送响应信息。