一、实现“Hello World!”及相关API介绍
使用 HTTP 服务器和客户端必须使用 require(‘http‘)
Node.js 中的 HTTP 接口设计主要是为了支持 传统的很难使用的多特性的协议,尤其是大量的信息。接口没有缓冲整个接收和相应,用户可使用流式数据。
HTPP信息的头部是像一个对象那样描述的:
{ ‘content-length‘: ‘123‘, ‘content-type‘: ‘text/plain‘, ‘connection‘: ‘keep-alive‘, ‘host‘: ‘mysite.com‘, ‘accept‘: ‘*/*‘ }
http.createServer([requestListener])
Returns: <http.Server>
返回一个新的 http.Server 的实例
requestListener 是一个自动添加 ‘request‘
的函数
server.listen([port][, hostname][, backlog][, callback])
开始接受指定的端口号(port)和主机名(hostname)之间的连接。
参数类型:
port:Number
hostname:String
backlog:Number
callback:Function
如果省略了 hostname,当IPV6可用时,服务器将连接任意的IPV6地址(::
),或者是任意的IPV4地址 (0.0.0.0
)
忽略 port 参数或者使用 0 作为端口号,如果想让操作系统随机分配一个端口号,可以在 ‘listening‘
事件之后使用 server.address().port 来重新取回
如果想要监听 unix 套接字,可以用一个文件名来替换 port 和 hostname
backlog 是连接请求队列的最大长度,实际的长度将由你的 OS 通过系统调用设置来决定,比如 linux 上的 tcp_max_syn_backlog 和 somaxconn 。这个参数的默认值是511(不是512)
callback 作为 ‘listening‘
事件的一个监听器, 是一个异步的回调函数
response.writeHead(statusCode[, statusMessage][, headers])
给请求消息发送一个响应头
statusCode Number 类型, 是一个三位数的 HTTP 状态码 比如:404
statusMessage String 类型,是可选的,主要是提高可读性
headers Object 类型, 是一个响应头,第二个参数是可选的
例如:
var body = ‘hello world‘;response.writeHead(200, { ‘Content-Length‘: Buffer.byteLength(body), ‘Content-Type‘: ‘text/plain‘ });
此方法在一个消息上只能调用一次,且必须在 response.end()
之前调用
response.end([data][, encoding][, callback])
这个方法是用来告诉服务器,所有的响应头和响应主体已经发送完毕,服务器就会知道这个消息已经完成了。每一个响应消息都必须调用 response.end()
encoding
<String>
callback
<Function>
如果指定了 data ,就相当于在 response.end(callback) 之前调用了 response.write(data, encoding)
如果指定了 callback ,将在响应流结束之后调用
结合以上内容,我们再来看一下经典的 Node.js 入门案例,在页面打印“Hello World”
基本的骨架:
//第一步: 引入 http 模块 var http = require(‘http‘); //第二步:创建一个服务器(requestListener 是一个函数,里面有2个参数,一个请求消息,一个响应消息) var server = http.createServer(function(req, res){ }); //第三步:服务器监听本地的82端口 server.listen(8082, ‘127.0.0.1‘);
设置消息内容:
var server = http.createServer(function(req, res){ //req -> request,表示请求; res -> response,表示响应 //设置响应头,第一个参数是3位数的HTTP状态码,第二个参数可选,第三个参数是一个对象,里面可存放合法的MIME类型 //MIME类型:文件类型是纯文本,字符集编码方式是 utf8 res.writeHead(200,{‘Content-Type‘: ‘text/plain; charset=utf8‘}); //响应消息发送结束,如果指定了data参数,就相当于在 res.end() 之前添加了一个 res.end(data, encoding) 方法 //res.end(‘Hello World!‘, ‘utf8‘); res.end(‘Hello World!‘); });
通过命令行工具挂起服务器,打开浏览器,在地址栏输入: 127.0.0.1:8082
同时,也可以打开控制台查看请求头部
值得注意的是,如果省略了 res.end(), 页面是渲染不出来的,因为服务器会一直处于等待状态,没人告诉它响应消息是否结束了
在 Node.js 三大特点详解 一文中,我们了解到传统的 HTTP服务器一般建立在 Apache、Nginx、IIS等服务器上,而 Node.js 并不需要,由于 Node.js 提供了 http 模块,自身就可以构建服务器(从上面的例子可以体会到)。
http 模块 是通过 C++实现的,性能非常可靠,其中,封装了一个 http 服务器 和一个简易的 http 客户端。http.Server 是一个基于事件的 http 服务器,http.request 则是一个 http 客户端工具,用于向 http 服务器发起请求
前面提到的 http.createServer( requestListener ) 方法中,requestListener 是一个回调函数,函数有2个参数 request 和 response,request 是 http.IncomingMessage 对象的实例,response 是 http.ServerResponse 对象的实例。下面分别来学习 HTTP 服务器 和 HTTP 客户端。
二、HTTP 服务器
先回顾下“Hello World!”这个例子
//第一步: 引入 http 模块 var http = require(‘http‘); //第二步:创建一个服务器(requestListener 是一个函数,里面有2个参数,一个请求消息,一个响应消息) var server = http.createServer(function(req, res){ //req -> request,表示请求; res -> response,表示响应 //设置响应头,第一个参数是3位数的HTTP状态码,第二个参数可选,第三个参数是一个对象,里面可存放合法的MIME类型 //MIME类型:文件类型是纯文本,字符集编码方式是 utf8 res.writeHead(200,{‘Content-Type‘: ‘text/plain; charset=utf8‘}); //响应消息发送结束,如果指定了data参数,就相当于在 res.end() 之前添加了一个 res.end(data, encoding) 方法 //res.end(‘Hello World!‘, ‘utf8‘); res.end(‘Hello World!‘); }); //第三步:服务器监听本地的82端口 server.listen(8082, ‘127.0.0.1‘);
基本的结构是直接创建一个 http 对象,然后创建一个 http 对象的实例 server,并为其监听82端口
1、http.Server
http.Server 继承自 net.Server
而 net.Server是一个 EventEmitter
,主要用来创建一个 TCP或者本地服务器。
事实上,Node.js 中大部分模块都继承自 EventEmitter,包括fs、net等模块,这也是为什么说 Node.js 基于事件驱动。http.Server 提供的事件如下:
request
客户端发出请求时触发,每一次连接可能会发出很多个请求(假如是持久连接的话)。提供两个参数request 和 response,是最常用的事件
request
<http.IncomingMessage>
response
<http.ServerResponse>
connection
当 TCP 建立连接时,触发此事件,提供一个参数 socket,是 net.socket 的实例
socket
<net.Socket>
close
当服务器关闭时,触发此事件。注意不是用户断开连接时
除此之外还有 checkContinue,upgrade,clientError 等事件,只有在实现复杂的 HTTP 服务器的时候才会用到。
在这些事件中,最常用的就是 request 事件,所以,http 提供了一个捷径:http.createServer( requestListener ),如我们所知,功能就是创建一个 HTTP 服务器并将 requestListener 作为 request 事件的监听函数,
2、http.IncomingMessage --> request
http.IncomingMessage 是 HTTP 请求的信息,一般由 http.Server 的 request 事件发送,并作为第一个参数传递,http 请求一般包括 请求头部 和 请求主体。
其提供了三个事件用于控制请求体传输:
data: 当请求体数据到来时,触发该事件。该事件提供一个参数 chunk,表示接收到的数据。如果该事 件没有被监听,那么请求体将会被抛弃,该事件可能会被调用多次
end:当请求体数据传输完成时,该事件被触发,此后将不会再有数据到来
close:用户当前请求结束时,该事件被触发。不同于end,如果用户强制终止传输,也还是调用 close
http.IncomingMessage 的属性如下:
3、http.ServerResponse ---> response
http.ServerResponse 是返回给客户端的信息,决定了用户最终能看到的结果。它是由 http.Server 的 request 事件发送的,作为第二个参数传递,一般简称为 response 或 res
http.ServerResponse 有三个重要的成员函数,用于返回响应头、响应内容以及结束请求(上面已经介绍过,这里再复习一次)
response.writeHead(statusCode[, statusMessage][, 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 客户端
http 模块提供了两个函数 http.request 和 http.get,功能是作为客户端向 HTTP 服务器发起请求
1、http.request(options, callback) 发起 HTTP 请求
接受两个参数,options表示请求的参数,可以是一个对象或字符串,如果是字符串的话,将自动调用 url.parse()
解析;
callback 是请求的回调函数,需要传递一个参数
options 常用的参数如下:
host:请求网站的域名或 IP 地址
port:请求网站的端口号,默认 80
method:请求方法,默认是 GET
path:请求的相对于根的路径,默认是“/”。QueryString 应该包含在其中,例如:/search?query=byvoid
headers:一个关联数组对象,为请求头的内容
http.request() 返回一个 http.ClientRequest
的实例
示例代码:
var http=require("http"); var options={ hostname:"www.12306.cn", port:80 }; var req=http.request(options,function(res){ res.setEncoding("utf-8"); res.on("data",function(chunk){ console.log(chunk.toString()) }); console.log(res.statusCode); }); req.on("error",function(err){ console.log(err.message); }); req.end();
我们运行这段代码,就可以在控制台中看到 12036 的 HTML 代码了
2、http.get(options, callback)
由于大多数的 GET 请求都没有主体,所以 Node.js 提供了这个简便的方法用于处理 GET 请求。
此方法是 http.request 的简化版,唯一的区别在于 http.get 自动将请求方法设为了 GET 请求,同时不需要手动调用 req.end()
var http = require(‘http‘); http.get({host: ‘www.12306.cn‘}, function(res) { res.setEncoding(‘utf8‘); res.on(‘data‘, function (data) { console.log(data); }); });
运行这段代码,一样可以在控制台得到 12036 的 HTML 代码
3、http.ClientRequest
http.ClientRequest 是由 http.request 或 http.get 返回产生的对象,表示一个已经产生而且正在进行中的 HTTP 请求。
它提供了一个 response 事件,即 http.request 或 http.get,第二个参数指定的回调函数的绑定对象。我们可以显示地绑定这个事件的监听函数:
var http = require(‘http‘); var req = http.get({host: ‘www.12306.cn‘}); req.on(‘response‘, function(res) { res.setEncoding(‘utf8‘); res.on(‘data‘, function (data) { console.log(data); }); });
运行这段代码,一样可以在控制台得到 12036 的 HTML 代码
http.ClientRequest 像 http.ServerResponse 一样也提供了 write 和 end 函数,用于向服务器发送请求体,通常用于 POST、PUT 等操作。所有写结束以后必须调用 end 函数以通知服务器,否则请求无效。
http.ClientRequest 还提供了以下函数。
request.abort():终止正在发送的请求。
request.setTimeout(timeout, [callback]):设置请求超时时间,timeout 为毫秒数。当请求超时以后,callback 将会被调用。
4、http.ClientResponse
http.ClientResponse 与 http.ServerRequest 相似,提供了三个事件 data、end和 close,分别在数据到达、传输结束和连接结束时触发,其中 data 事件传递一个参数chunk,表示接收到的数据。
http.ClientResponse 也提供了一些属性,用于表示请求的结果状态
http.ClientResponse 还提供了以下几个特殊的函数。
response.setEncoding([encoding]):设置默认的编码,当 data 事件被触发时,数据将会以 encoding 编码。默认值是 null,即不编码,以 Buffer 的形式存储。常用编码为 utf8。
response.pause():暂停接收数据和发送事件,方便实现下载功能。
response.resume():从暂停的状态中恢复。
本文出自 “dapengtalk” 博客,请务必保留此出处http://dapengtalk.blog.51cto.com/11549574/1889787
原文:http://dapengtalk.blog.51cto.com/11549574/1889787