nodejs的某些api~,五 HTTP模块

HTTP的模块是nodejs最重要的模块(应该是),最近在看HTTP权威指南,重新过了一遍http协议和web客户端。再来看这个http。

HTTP构建于TCP之上,属于应用层协议,继承自tcp服务器(net模块),它能与多个客户端保持连接,由于基于事件驱动,并不为每个连接创建额外的进程或线程,所以能实现高并发;HTTP服务器与TCP服务器有区别的地方在于,在开启keepalive后,一个tcp会话可以用于多次请求和响应。TCP服务是以connection为单位进行服务,HTTP是以request为单位进行服务,HTTP模块就是将connection到request的过程进行了封装。

http模块将连接所用的套接字的读写抽象为serverRequest和serverResponse对象,他们分别对应请求和响应。在请求产生过程中,http模块拿到连接中的数据,调用二进制模块http_parser进行解析,解析玩报文的报头后,触发request事件,调用用户的业务逻辑。

HTTP的消息头通过对象表示

{ 'content-length': '123',

'content-type': 'text/plain',

'connection': 'keep-alive',

'host': 'mysite.com',

'accept': '*/*' }

http.STATUS_CODES//例如http.STATUS_CODES[404]==='Not Found';

http.createServer([requestListener]);//返回一个新的web服务器对象;

类http.Server这是一个包含下列事件的EventEmitter

事件'request'function(request,response){}

//每次收到一个请求时触发,每个链接又可能有多个请求;

//request是http.IncomingMessage的一个实例.response是http.ServerResponse的一个实例;

事件'connection' function(socket){}

//新的TCP流建立时触发。socket是一个net.Socket对象。通常用户无需处理改时间

事件'close'

事件'checkContinue'//每次收到Expect:100-continue的http请求时触发。如果未监听该事件,服务器会酌情发送100Continue响应

事件'connect' function(request,socket,head){}//每次客户端发起CONNECT请求时触发。如果未监听该事件,客户端发起CONNECT请求时连接会被关闭

//request是该http请求的参数;head是一个Buffer实例,隧道流的第一个包,可能为空

//这个世界被分发后,请求的套接字将不会有data事件监听器,你需要绑定一个监听器到data事件,处理套接字被发送到服务器的数据

事件'upgrade' function(request,socket,head){}//每当一个客户端请求http升级时触发;需要绑定data监听器

事件'clientError'function(exception,socket){}//客户端触发一个error事件,被转发到此;

server.listen(port,[hostname],[cb],[backlog],[callback])//开始在指定的主机名和端口接收连接

//积压量backlog为连接等待队列的的最大长度。

server.listen(path,[cb]);//启动一个unix套接字在所给路径path上监听连接;

server.close([cb])//仅在服务端接收新连接

server.maxHeadersCount//最大请求头目现在,默认1000个

server.setTimeout(msecs,cb);//设置超时值,若超时,分发’timeout‘事件,同时将套接字做参传入;

server.timeout//一个套接字被判为超时之时闲置的毫秒数;

类http.ServerResponse//这是一个由HTTP服务器内部创建的对象,他将做为2参传递到'request'事件中;实现了weitable Stream接口,是一个包含下列事件的EventEmitter

事件'close' function(){}//底层连接在response.end()或被调用或可以冲洗掉之前就被终结了。;

response.writeContinue()//发送一个HTTP/1.1 100 Continue消息至客户端,表明请求体可被发送;

response.writeHead(statusCode,[reasonPhrase],[headers])//向请求恢复响应头,statusCode是一个3位HTTP状态码;

//headers是响应头的内容。把人类可读的‘原因短句’作为第二个参数;

response.setTimeout(msecs,cb);

response.statusCode//使用默认headers时,这个属性决定headers更新时被传回客户端的http状态码;

response.setHeader(name,value)//为默认或已存在的头设置一条单独的头内容,如果已存在于将被送出的头重,将会覆盖其如果想设置更多的头,就会使用一个相同名字的字符串数组。

·response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);

·response.setHeader("Content-Type","text/html");

response.headersSent//如果headers发送完毕为true,反正为false;

response.sendData//若为true,则当headers里没有Date值时自动生成Date并发送,默认true;

response.getHeader(name)//读取一个在队列中但还没有被发送只客户端的header

response.removeHeader(name)//取消一个在队列内等待发送的header

response.write(chunk,[encoding])//发送一个响应体的数据块,可能被调用多次以防继承部分响应体;

//chunk可以是字符串或缓存,若为字符串,2参表明如何将一个字符串编码为一个比特流。

response.addTrailers(headers)//这个方法添加HTTP尾随headers给响应;

//只有当数据块编码被用于响应时尾随才会被触发,如果不是,会被自动丢弃;

//如果触发尾随消息,HTTP要求一个报文头场列表和Trailer报头一起发送;

response.writeHead(200, { 'Content-Type': 'text/plain',

'Trailer': 'Content-MD5' });

response.write(fileData);

response.addTrailers({'Content-MD5': "7895bf4b8828b55ceaf47747b4bca667"});

response.end();

response.end([data],[encoding]);//当所有响应报头和报文被发送完成时,这个方法将信号发送给服务器,服务器会认为消息完成了,每次响应完成必须调用此;

http.request(options,cb);

//node维护几个连接每个服务器的HTTP请求,这个函数允许后台发布请求。

//options可以是一个对象或一个字符串。如果options是一个字符串,它将自动使用url.parse()解析;

host:请求发送到的服务器的域名或IP地址。默认为'localhost'。

hostname:用于支持url.parse()。hostname比host更好一些

port:远程服务器的端口。默认值为80。

localAddress:用于绑定网络连接的本地接口。

socketPath:Unix域套接字(使用host:port或socketPath)

method:指定HTTP请求方法的字符串。默认为'GET'。

path:请求路径。默认为'/'。如果有查询字符串,则需要包含。例如'/index.html?page=12'。请求路径包含非法字符时抛出异常。目前,只否决空格,不过在未来可能改变。

headers:包含请求头的对象。

auth:用于计算认证头的基本认证,即'user:password'

agent:控制Agent的行为。当使用了一个Agent的时候,请求将默认为Connection: keep-alive。可能的值为:

undefined(默认):在这个主机和端口上使用[全局Agent][]。

此例构造了一个http客户端,node模拟的客户端请求。

var options={
    hostname:‘127.0.0.1’,
    port:1334,
    path:'/',
    method:'GET'
}
var req=http.request(options,function(res){
   console.log('STAUS: '+res.statusCode);
   console.log('HRADERS: '+JSON.stringify(res.headers));
   res.setEncoding(utf8);
   res.on('data',function(chunk){
       console.log(chunk);
   })   
})
req.end()

Agent对象:在Agent中显式使用passed。

false:在对Agent进行资源池的时候,选择停用连接,默认请求为:Connection: close。

keepAlive:{Boolean} 保持资源池周围的套接字在未来被用于其它请求。默认值为false

keepAliveMsecs:{Integer} 当使用HTTP KeepAlive的时候,通过正在保持活动的套接字发送TCP KeepAlive包的频繁程度。默认值为1000。仅当keepAlive被设置为true时才相关。

//http.request()返回一个http.ClientRequest类的实例。ClientRequest实例是一个可写流对象,如果需要用post请求上传一个文件的话,将其写入到ClientRequest对象;

http.get(options,cb)//与http.request()唯一区别是它设置的是get方法并自动调用req.end();

http.get("http://www.google.com/index.html", function(res) {
  console.log("响应:" + res.statusCode);
}).on('error', function(e) {
  console.log("错误:" + e.message);
});

类http.Agent

//用于把套接字做成资源池,用于http客户端请求;

http服务器默认的客户端代理对象http.globalAgent,它对每个服务器端创建的连接进行管理,默认情况下,对同一个服务器端发起的http请求最多创建5个链接,它的实质是一个连接池。

我们可以自行构造代理对象。

var agent=new http.Agent({
   maxSockets:10 
})
var options={
    hostname:"127.0.0.1",
    post:1334,
    path:"/",
    method:"GET",
    agent:agent
};

也可以设置agent为false,就脱离连接池的管理,使请求不受并发的限制。

http Agent把客户端请求默认使用Connection:keep-alive。如果没有http请求在等待成为空闲的套接字,那么套接字将关闭。

当套接字触发了close事件或特殊的agentRemove事件的时候,套接字从agent资源池中移出。

如果你打算保持一个http请求长时间开启,并不希望它保持在资源池中,那么你可以按照下列代码:

http.get(options,function(res){
    //..dosomething
}).on('socket',function(socket){
    socket.emit('agentremove')
})
可用agent:false选择完全停用资源池;
http.get({
    hostname:'localhost',
    port:80,path:'/',agent:false,
},function(res){//..})

类http.ClientRequest

//该对象在内部创建,并由http.request()返回。他表示着一个正在处理的请求,其头部已经进入请求队列。

//该头部仍可以通过setHeader(name,value),getHeader(name),removeHeader(name)等api修改;

//为了获取响应对象,给请求对象添加一个'response'监听器。当接收到响应头时,请求对象会触发'response',该事件执行时有一个参数,参数为http.IncomingMessage的一个实例

在'response'事件期间,可以为响应对象添加监听器,尤其是'data事件'。

Event 'response'

function(res){}//当接收到请求的响应时触发,只被触发一次。response参数是http.http.IncomingMessage的一个实例;

事件'socket'//触发于一个套接字被赋予为这个请求的时候

事件'connect'//每次服务器使用connect方法响应一个请求时被触发。如果该事件未被监听,接收connect方法的客户端将关闭它们的连接;

socket.write('GET /HTTP/1.1\r\n'+'Host:www.google.com:80\r\n'+'Connection:close\r\n'+'\r\n');
socket.on('data',function(chunk){
    console.log(chunk.toString());
})
socket.on('end',function(){
    proxy.close();
})

事件'upgrade' function(response,socket,head){}

//每次服务器返回upgrade响应时触发。如果事件为被监听,客户端收到upgrade后将关闭连接

req.on('upgrade',function(res,socket,upgradeHead){
    console.log('got upgrade!');
    socket.end();
    process.exit(0);
})

事件'continue'

//当服务器发送100 continue响应时触发,通常是因为请求保护Expect:100-contine,该指令表示客户端应发送请求体。

request.write(chunk,[encoding])

//发送一块请求体。调用多次。用户可以流式发送请求体至服务器--在这种情况下,创建请求时建议使用['Transfer-Encoding','chunked']当所有响应报头和报文被发送完成时,这个方法将信号发送给服务器,服务器会认为消息完成了,每次响应完成必须调用此;

request.end([data],[encoding])

//结束发送请求。

request.abort()//终止一个请求;

request.setTimeout(timeout,[cb])//一旦一个套接字被分配给该请求并且完成连接,socket.setTimeout()将被调用

request.setNoDelay([noDelay])//一旦一个套接字被分配到一个请求 同上

http.http.IncomingMessage; 一个IncomingMessage对象由http.server或者http.http.ClientRequest创建的。并作为第一参数分别传递给'request'和'response'事件。它也可以被用来访问应答的状态,头文件和数据。’

事件'close'表示在response.end()被掉用或强制刷新之前,底层的连接已经被终止了。