您正在查看: Node.js 分类下的文章

The NodeJS http.ServerResponse

http.ServerResponse

这个对象一般由HTTP 服务器建立而非用户自己手动建立。它作为'request'事件的第二个参数,这是一个可写流。

response.writeHead(statusCode, [reasonPhrase], [headers])

这个方法的是用来发送一个响应报文头给本次的请求方,第一个参数状态码是由一个3位数字所构成的HTTP 状
态,比如404之类的。最后一个参数headers 是响应头具体内容.也可以使用一个方便人们直观了解的reasonPhrase
作为第二个参数。
例如:

var body = 'hello world';
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
});```

在一次完整信息交互中此方法只能调用一次,并且必须在调用response.end()之前调用。


response.write(chunk, encoding='utf8')```

此方法必须在writeHead 方法调用后才可以被调用,他负责发送响应报文中的部分数据。如果要发送一个报文
体的多个部分,则可以多次调用此方法。

参数chunk 可以是一个字符串或者一个buffer。如果chunk 是一个字符串,则第二个参数指定如何将这个字符串
编码成字节流,缺省情况下,编码为'utf8'。

注意:这是一个原始格式http 报文体,和高层协议中的多段消息体编码格式({'Transfer-Encoding':'chunked'})无关。
第一次调用response.write()时,此方法会将已经缓冲的消息头和第一块消息体发送给客户。当第二次调用
response.write()的时候,node 将假定你想要以流的形式发送数据(分别发送每一个数据块并不做缓存)。这样,
其实response 对象只是缓存消息体的第一个数据块。

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

这个方法会告诉服务器此响应的所有报文头及报文体已经发出;服务器在此调用后认为这条信息已经发送完毕;
这个方法必须对每个响应调用一次。

如果指定data 参数,他就相当于调用了response.write(data, encoding)然后跟着调用了response.end()。

The NodeJS Modules 模块

Modules 模块

Node 使用CommonJS 的模块系统。
Node 同时也拥有一个简单的模块加载系统。在Node 的世界里,文件和模块是一一对应的,比如,以下的程序
foo.js 会向大家演示加载同一目录下的circle.js 模块。

The contents of foo.js:
foo.js 的代码:

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));```

The contents of circle.js:
cirle.js 的代码:


var PI = 3.14;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};```

模块circle.js 有两个方法area()和circumference()。为了使其对外可见,将其导出到一个特殊的对象exprots(还
可以用this 来替代exports)。此模块中的本地变量是私有的。在这个例子中,PI 便是circle 模块的似有变量,puts()
方法则是引用自系统自带模块'sys'。没有'./'前缀的模块都是写内建的。我们将会详细讲解这个特性。

使用'./'前缀加载的模块必须和加载模块的文件位于同一文件夹下,所以将circle.js 和foo.js 放在同一目录下。
如果不用'./'前缀,比如require('assert'),那么则会在require.paths 数组指定的路径下寻找,require.paths 在我的机
器上输出如下:

[ '/home/ryan/.node_libraries' ] [ '/home/ryan/.node_libraries' ]
所以当呼叫require('assert')是,系统会沿着如下路径寻找该模块:

  • 1: /home/ryan/.node_libraries/assert.js
  • 2: /home/ryan/.node_libraries/assert.node
  • 3: /home/ryan/.node_libraries/assert/index.js
  • 4: /home/ryan/.node_libraries/assert/index.node

有'.node'后缀的模块是Node 系统的二进制模块:可以参考'Addons'来得到更多信息。'index.js'允许我们把一个模块
作为一个目录打包。

require.paths 可以在运行时修改或者在类UNIX 系统下通过修改NODE_PATH 环境变量来达到同样的目的。

The NodeJS net.Server TCP服务器模块

net.Server TCP服务器模块

这个类(net.Server)是用来建立TCP 或者UNIX 服务器的。
下面有一个在8124端口等待连结的echo server 的例子:

var net = require('net');
var server = net.createServer(function (stream) {
stream.setEncoding('utf8');
stream.on('connect', function () {
stream.write('hello\r\n');
});
stream.on('data', function (data) {
stream.write(data);
});
stream.on('end', function () {
stream.write('goodbye\r\n');
stream.end();
});
});
server.listen(8124, 'localhost');```

如果要使用UNIX SOCKET '/tmp/echo.sock',最后一行需要改成。

server.listen('/tmp/echo.sock');```

如下是该对象可以触发的事件:

Event: 'connection'

function (stream) {}```

当一个新连接建立后触发(发出)这个事件,stream 是net.Stream 类的一个实例。


**Event: 'close'**

function () {}```

当一个SERVER 关闭的时候触发(发出)这个事件。

net.createServer(connectionListener)

建立一个新的TCP SERVER。connectionListener 参数会自动设置为'connection'事件的监听函数。

server.listen(port, [host], [callback])

在指定端口和主机上接受一个连接请求。如果HOST 这个参数忘记写了,该SERVER 将在机器的所有IPV4地
址(INADDR_ANY)上接受连接请求。

这是一个异步函数,最后一个参数‘callback’将在服务器被绑定(应当是指当listen 正常执行完并且进入正常监听
流程后)后被调用。

server.listen(path, [callback])

建立一个UNIX SOCKET SERVER 并监听在指定路径上的连接。
这个函数是一个异步方法,最后一个参数‘callback’将在服务器被绑定(应当是指当listen 正常执行完并且进入正
常监听流程后)后被调用。

server.listenFD(fd)

建立一个SERVER 并监听在给定的文件描述符上。
这个文件描述符必须是已经在其上调用过bind(2)、listen(2)系统调用的。

server.close()

停止服务器,此函数是异步的。服务器在触发'close'事件后才会最终关闭。

The NodeJS http.Client

http.Client

使用服务器地址作为参数来构造一个HTTP client,其返回的句柄可用来发出一个或者多个请求。根据连接的服
务器不同,这个客户端可以使用管道处理机制来处理请求或者每个请求重新构建stream。当前的实现方式并没
有用管道处理机制处理请求.

Example of connecting to google.com:
var http = require('http');
var google = http.createClient(80, 'www.google.com');
var request = google.request('GET', '/',
{'host': 'www.google.com'});
request.end();
request.on('response', function (response) {
console.log('STATUS: ' + response.statusCode);
console.log('HEADERS: ' + JSON.stringify(response.headers));
response.setEncoding('utf8');
response.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});

如下消息头应当注意:

Node 并不会添加'Host',但是这个属性对于一个网站来说通常是必须的。

发送'Connection: keep-alive'将告知Node 和服务器之间的连接应当是持久连接,直到下一次请求才断开。
发送'Content-length'标记将禁用默认的消息体编码。

Event: 'upgrade'

function (request, socket, head)```

当服务器响应upgrade 请求时触发此事件,如果这个消息没有被监听,客户端接收到一个upgrade 头的话会导致
这个连接被关闭。


可以查看http.Server 关于upgrade 事件的解释来了解更多内容。


**http.createClient(port, host='localhost', secure=false, [credentials])**


构造一个新的HTTP 客户端.port 和host 指明了将要连接的目标。在发出请求之前不会建立流(establishe a stream)。
secure 是一个可选的布尔值,用来表示是否启用HTTPS。credentials 是一个来自于crypto 模块的可选参数,
credentials 中可以包含client 的私钥,证书以及一个可信任的数字认证中心的证书列表.
如果连接使用了secure 但是没有把数字认证中心证书传给credentials,那么NODEJS 将缺省使用公开的可信任
数字认证中心整数列表,就比如http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt


**client.request(method='GET', path, [request_headers])**


发出一个请求,在必须时建立一个流。该函数返回一个http.ClientRequest 对象。method 是可选项,缺省会以
GET 方式发出请求


request_headers 是可选项。请求头的额外部分一般由NODE 内部实现。该函数返回一个ClientRequest 对象
如果你就想要发送一个信息体,记得要在头信息里包含Content-Length 项。如果你想要将BODY 通过流的方式
传输发送,或许需要设置Transfer-Encoding: chunked.


译注:大多数的站点相应用户请求时发送的HTTP Headers 中包含Content-Length 头.此头信息定义在HTTP1.0协
议RFC 1945 10.4章节中.该信息是用来告知用户代理,通常意义上就是浏览器,服务端发送的文档内容长度.浏览
器接受到此信息后,接收完Content-Length 中定义的长度字节后开始解析页面.如果服务端有部分数据延迟发送,那么浏览器就会白屏.这样导致比较糟糕的用户体验. 解决方法在HTTP1.1协议.RFC2616中14.41章节中定义的
Transfer-Encoding:chunked 的头信息.chunked 编码定义在3.6.1中.根据此定义浏览器不需要等到内容字节全部下
载完成,只要接收到一个chunked 块就可解析页面.并且可以下载html 中定义的页面内容,包括js,css,image 等.


注意:这个请求并不完全。这个方法仅仅发送了头和请求。需要发送一个request.end()来真正的完成当前这个请
求并且接收回应。(这听起来有点绕,但是这正好就提供了用户通过使用request.write()方法来通过流方式发送
body 到服务器端的机会)


**client.verifyPeer()**


返回true/false 并在上下文附带服务器定义的或者缺省数字认证中心的有效证书列表。


**client.getPeerCertificate()**


返回用JSON 结构详尽表述的服务器方证书,其中包含证书的‘主题’,‘发布者’,'有效来源','有效目标'('subject',
'issuer', 'valid_from' and 'valid_to')。

The NodeJS http.ClientRequest

http.ClientRequest

http.Client 的request()方法建立并返回http.ClientRequest 对象。该对象代表一个进行中的请求(request),该请求
的消息头已经发送出去。

要获得回应,可以为request 对象增加一个'response'事件的监听器。‘response’事件将在request 对象接收到响应
头的时候被触发,'response'事件的处理函数接收一个参数,该参数是http.ClientResponse 的实例。

在'response'事件中,可以为response 对象增加监听器,监听'data'事件尤为有用。要记住,'response'事件是在接
收到回应信息体之前被触发,所以这里不需要担心信息体的第一部分不能被捕获。只要在处理'response'事件过
程中增加'data'事件监听器,信息体是肯定可以被捕获的。

// Good
request.on('response', function (response) {
response.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
// Bad - misses all or part of the body
request.on('response', function (response) {
setTimeout(function () {
response.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
}, 10);
});```

这是一个可写流

如下是此对象可以触发的事件。


**Event 'response'**

function (response) { }```

在响应被接收后触发。这个事件仅会被发出一次,参数response 是http.ClientResponse 的实例。

request.write(chunk, encoding='utf8')

发送body 中的一块。用户可以通过多次调用这个方法将请求数据包通过流的方式发送到服务器。在这个时候我
们建议使用在建立请求的时候把['Transfer-Encoding', 'chunked']放在请求头里。
参数'chunk'应当是一个数字索引的数组或字符串。

参数'encoding'是可选的,仅在chunk 为字符串的时使用。

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

完成本次请求的发送。如果消息体中的任何一个部分没有来得及发送,request.end 将把他们全部刷新到流中。
如果本次请求是分块的,这个函数将发出结束字符'0\r\n\r\n'。

如果使用参数data,就等于在调用request.write(data, encoding)之后紧接着调用request.end()。