NodeJS的核心模块http服务器端
HTTP服务器
http.Server是http模块中的HTTP服务器对象,它提供了一套封装级别很低的API,仅仅是流控制和简单的消息解析,所有的高层功能都要通过它的接口来实现。
http.createServer创建一个http.Server的示例,将一个函数作为HTTP请求处理函数。这个函数接受两个参数,分别是请求对象(req)和响应对象(res)。
1.http.Server的事件
http.Server是一个基于事件的HTTP服务器,所有的请求都被封装为独立的事件,开发者只需要对它的事件编写响应函数即可实现HTTP服务器的所有功能。它集成自EventEmitter,提供了以下几个事件。
- request:当客户端请求到来时,该事件被触发,提供了两个参数req和res,分别是http.ServerRequest和http.ServerResponse的实例,表示请求和响应信息。
- connection:当TCP连接建立时,该事件被触发,提供一个参数socket,为net.Socket的实例。connection事件的粒度要大于request,因为客户端在Keep-Alive模式下可能会在同一个连接内发送多次请求。
2.http.ServerRequest
http.ServerRequest是HTTP请求的信息,是后端开发者最关注的内容。它一般由http.Server的request事件发送,作为第一个参数传递,通常简称为request或req。ServerRequest提供了一些属性,见下表。
名称 | 含义 |
---|---|
complete | 客户端请求是否已经发送完成 |
httpVersion | HTTP协议版本,通常是1.0或1.1 |
method | HTTP请求方法,如get,post,put,delete等 |
url | 原始的请求路径,例如/static/image/x.jpg或/user?name=byvoid |
headers | HTTP请求头 |
trailers | HTTP请求尾(不常见) |
connection | 当前HTTP连接套接字,尾net.Socket的实例 |
socket | connection属性的别名 |
client | client属性的别名 |
HTTP请求一般可以分为两部分:请求头(Request Header)和请求体(Request Body)。请求头内容由于长度较短都可以在请求头解析完成后立即读取。而请求体可能相对较长,需要一定的事件传输,因此http.ServerRequest提供了一下3个事件用于控制请求体传输。
- data:当请求体数据到来时,该事件被触发。该事件提供一个参数chunk,表示接收到的数据。如果该事件没有被监听,那么请求体将会被抛弃。该事件可能会被调用多次。
- end:当请求体数据传输完成时, 该事件被触发,此后,将不会再有数据到来。
- close:用户当前请求结束时,该事件被触发。不用于end,如果用户强制终止传输,也还是调用close。
3.获取Get请求的内容
注意,http.ServerRequest提供的属性中没有类似于PHP语言中的
//httpserverrequestget.js
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);
我们可以看到浏览器返回的结果:
{
search: '?name=byvoid&[email protected]',
query: {name: 'byvoid', email: '[email protected]'},
pathname: '/user',
path: '/user?name=byvoid&[email protected]',
href: '/user?name=byvoid&[email protected]'
}
通常url.parse,原始的path被解析为一个对象,其中query就是我们所谓的GET请求的内容,而路径则是pathname。
4.获取 POST请求内容
HTTP协议1.1版本提供了8中标准的请求方法,其中最常见的就是GET和POST。相比GET请求把所有的内容编码到访问路径中,POST请求的内容全部都在请求体中。http.ServerRequest并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作,譬如上传文件。而很多时候我们可能并不需要理会请求体的内容,恶意的POST请求会大大消耗服务器的资源。所以Node.js默认是不会解析请求体的,当你需要的时候,需要手动来做。让我们看看实现方法:
//httpserverrequestpost.js
var http = require('http');
var querystring = require('querystring');
var util = require('util');
http.createServer(function(req, res){
var post = '';
req.on('data', function(chunk){
post += chunk;
});
req.on('end', function(){
post = querystring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
上面代码并没有在请求响应函数中向客户端返回信息,而是定义了一个post变量,用于在闭包中暂存请求体的细信息。通过req的data事件监听函数,每当接收到请求体的数据,就累加到post变量中。在end事件触发后,通过querystring.parse将post解析为真正的post请求格式,然后向客户端返回。
5.http.ServerResponse
http.ServerResponse是返回给客户端的信息,决定了用户最终能看到的结果。它也是由http.Server的request时间发送的,作为第二个参数传递,一般简称为resposne或res。
http.ServerResponse有三个重要的成员函数,用户返回响应头、响应内容以及结束请求。
- response.writeHead(statusCode, [headers]):向请求的客户端发送响应头。statusCode是HTTP状态吗,如200(请求成功)、404(未找到)等。headers是一个类似关联数组的对象,表示响应头的每个属性。该函数在一个请求内最多只能调用一次,不过不调用,则自动生成一个响应头。
- response.write(data, [encoding]):向请求的客户端发送响应内容。data是一个Buffer或字符串,表示要发送的内容。如果data是字符串,那么需要制定encoding来说明它的编码方式,默认是utf-8。在response.end调用之前,response.write可以被调用多次。
- response.end([data], [encoding]):结束响应,告知客户端所有发送已经完成。当所有要返回的内容发送完毕的时候,该函数必须被调用一次。它接受两个可选参数,意义和response.write相同。如果不调用该函数,客户端将永远处于等待状态。
总结
http的服务器端在接受用户请求时,是通过事件触发。request和connection事件,常用的是request事件。服务器端在向客户端写数据时,调用的是方法函数。有三个函数writeHeader、write、end。注意,在返回数据时,必须要调用end方法,否则客户端会处于一直等待服务器返回数据的状态。