# HTTP
~~~
稳定度: 3 - 稳定
~~~
要使用HTTP服务器或客户端功能,需引用此模块`require('http')`.
Node中的HTTP接口的设计支持许多HTTP协议中原本用起来很困难的特性.特别是对于很大的或者块编码的消息.这些接口很谨慎,它从来不会完全缓存整个请求(request)或响应(response),这样用户可以在请求(request)或响应(response)中使用数据流.
HTTP 的消息头(Headers)通过如下对象来表示:
~~~
{ 'content-length': '123',
'content-type': 'text/plain',
'connection': 'keep-alive',
'host': 'mysite.com',
'accept': '*/*' }
~~~
其中键为小写字母,值是不能修改的。
为了能全面地支持可能的HTTP应用程序,Node提供的HTTP API都很底层。它处理的只有流处理和消息解析。它把一份消息解析成报文头和报文体,但是它不解析实际的报文头和报文体。
定义好的消息头允许多个值以`,`分割, 除了`set-cookie`和`cookie`,因为他们表示值的数组. 像 `content-length`这样只能有单个值的消息头直接解析, 并且只有单值可以表示成已解析好的对像.
接收到的原始头信息以数组形式 `[key, value, key2, value2, ...]` 保存在 `rawHeaders` 属性中. 例如, 前面提到的消息对象会有 `rawHeaders` 列表如下:
~~~
[ 'ConTent-Length', '123456',
'content-LENGTH', '123',
'content-type', 'text/plain',
'CONNECTION', 'keep-alive',
'Host', 'mysite.com',
'accepT', '*/*' ]
~~~
### http.STATUS_CODES
- {Object}
全部标准HTTP响应状态码的集合和简短描述。例如`http.STATUS_CODES[404] === 'Not Found'`。
### http.createServer([requestListener])
返回一个新的web服务器对象
参数 `requestListener` 是一个函数,它将会自动加入到 `'request'` 事件的监听队列.
### http.createClient([port], [host])
该函数已**弃用**,请用[http.request()](#)代替. 创建一个新的HTTP客户端. `port` 和`host` 表示所连接的服务器.
### Class: http.Server
这是一个包含下列事件的[EventEmitter](#):
### 事件 : 'request'
`function (request, response) { }`
每次收到一个请求时触发.注意每个连接又可能有多个请求(在`keep-alive`的连接中).`request`是`http.IncomingMessage`的一个实例.`response`是`http.ServerResponse`的一个实例
### 事件: 'connection'
`function (socket) { }`
新的TCP流建立时出发。 `socket`是一个`net.Socket`对象。 通常用户无需处理该事件。 特别注意,协议解析器绑定套接字时采用的方式使套接字不会出发`readable`事件。 还可以通过`request.connection`访问`socket`。
### 事件: 'close'
`function () { }`
当此服务器关闭时触发
### Event: 'checkContinue'
`function (request, response) { }`
每当收到Expect: 100-continue的http请求时触发。 如果未监听该事件,服务器会酌情自动发送100 Continue响应。
处理该事件时,如果客户端可以继续发送请求主体则调用`response.writeContinue`, 如果不能则生成合适的HTTP响应(例如,400 请求无效)。
需要注意到, 当这个事件触发并且被处理后, `request` 事件将不再会触发.
### 事件: 'connect'
`function (request, socket, head) { }`
每当客户端发起CONNECT请求时出发。如果未监听该事件,客户端发起CONNECT请求时连接会被关闭。
- `request` 是该HTTP请求的参数,与request事件中的相同。
- `socket` 是服务端与客户端之间的网络套接字。
- `head` 是一个Buffer实例,隧道流的第一个包,该参数可能为空。
在这个事件被分发后,请求的套接字将不会有`data`事件监听器,也就是说你将需要绑定一个监听器到`data`事件,来处理在套接字上被发送到服务器的数据。
### Event: 'upgrade'
`function (request, socket, head) { }`
每当一个客户端请求http升级时,该事件被分发。如果这个事件没有被监听,那么这些请求升级的客户端的连接将会被关闭。
- `request` 是该HTTP请求的参数,与request事件中的相同。
- `socket` 是服务端与客户端之间的网络套接字。
- `head` 是一个Buffer实例,升级后流的第一个包,该参数可能为空。
在这个事件被分发后,请求的套接字将不会有`data`事件监听器,也就是说你将需要绑定一个监听器到`data`事件,来处理在套接字上被发送到服务器的数据。
### Event: 'clientError'
`function (exception, socket) { }`
如果一个客户端连接触发了一个 'error' 事件, 它就会转发到这里.
`socket` 是导致错误的 `net.Socket` 对象。
### server.listen(port, [hostname], [backlog], [callback])
开始在指定的主机名和端口接收连接。如果省略主机名,服务器会接收指向任意IPv4地址的链接(`INADDR_ANY`)。
监听一个 unix socket, 需要提供一个文件名而不是端口号和主机名。
积压量 `backlog` 为连接等待队列的最大长度。实际长度由您的操作系统通过 sysctl 设置决定,比如 Linux 上的 `tcp_max_syn_backlog` 和 `somaxconn`。该参数缺省值为 511(不是 512)。
这个函数是异步的。最后一个参数`callback`会被作为事件监听器添加到 ['listening'](#)事件。另见[net.Server.listen(port)](#)。
### server.listen(path, [callback])
启动一个 UNIX 套接字服务器在所给路径 `path` 上监听连接。
该函数是异步的.最后一个参数`callback`将会加入到[`listening`][]事件的监听队列中.又见[net.Server.listen(path)](#).
### server.listen(handle, [callback])
- `handle`处理器 {Object}
- `callback`回调函数 {Function}
`handle` 变量可以被设置为server 或者 socket(任一以下划线开头的成员 `_handle`), 或者一个 `{fd: <n>}` 对象
这将使服务器用指定的句柄接受连接,但它假设文件描述符或者句柄已经被绑定在特定的端口或者域名套接字。
Windows 不支持监听一个文件描述符。
这个函数是异步的。最后一个参数`callback`会被作为事件监听器添加到['listening'](#)事件。另见[net.Server.listen()](#)。
### server.close([callback])
禁止服务端接收新的连接. 查看 [net.Server.close()](#).
### server.maxHeadersCount
最大请求头数目限制, 默认 1000 个. 如果设置为0, 则代表不做任何限制.
### server.setTimeout(msecs, callback)
- `msecs` {Number}
- `callback` {Function}
为套接字设定超时值。如果一个超时发生,那么Server对象上会分发一个`'timeout'`事件,同时将套接字作为参数传递。
如果在Server对象上有一个`'timeout'`事件监听器,那么它将被调用,而超时的套接字会作为参数传递给这个监听器。
默认情况下,服务器的超时时间是2分钟,超时后套接字会自动销毁。 但是如果为‘timeout’事件指定了回调函数,你需要负责处理套接字超时。
### server.timeout
- {Number} 默认 120000 (2 分钟)
一个套接字被判断为超时之前的闲置毫秒数。
注意套接字的超时逻辑在连接时被设定,所以更改这个值只会影响*新创建的*连接,而不会影响到现有连接。
设置为0将阻止之后建立的连接的一切自动超时行为。
### Class: http.ServerResponse
这是一个由HTTP服务器内部创建的对象(不是由用户自行创建)。它将作为第二个参数传递到`'request'`事件中。
该响应实现了 [Writable Stream](#) 接口。这是一个包含下列事件的 [EventEmitter](#) :
### 事件: 'close'
`function () { }`
需要注意的是,底层链接在`response.end()`被调用或可以冲洗掉之前就被终结了。
### response.writeContinue()
发送一个 HTTP/1.1 100 Continue 消息至客户端,表明请求体可以被发送。可以再服务器上查看['checkContinue'](#)事件。
### response.writeHead(statusCode, [reasonPhrase], [headers])
向请求回复响应头. statusCode是一个三位是的HTTP状态码, 例如 `404`. 最后一个参数, `headers`, 是响应头的内容. 可以选择性的,把人类可读的‘原因短句’作为第二个参数。
实例:
~~~
var body = 'hello world';
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
~~~
这个方法只能在当前请求中使用一次,并且必须在`response.end()`之前调用。
如果你在调用这之前调用了`response.write()`或者 `response.end()` , 就会调用这个函数,并且 不明/容易混淆 的头将会被使用。
注意:Content-Length 是以字节(byte)计,而不是以字符(character)计。之前的例子奏效的原因是字符串'hello world'只包含了单字节的字符。如果body包含了多字节编码的字符,就应当使用Buffer.byteLength()来确定在多字节字符编码情况下字符串的字节数。需要进一步说明的是Node不检查Content-Lenth属性和已传输的body长度是否吻合。
### response.setTimeout(msecs, callback)
- `msecs` {Number}
- `callback` {Function}
设定套接字的超时时间为`msecs`。如果提供了回调函数,会将其添加为响应对象的`'timeout'`事件的监听器。
如果请求、响应、服务器均未添加`'timeout'`事件监听,套接字将在超时时被销毁。 如果监听了请求、响应、服务器之一的`'timeout'`事件,需要自行处理超时的套接字。
### response.statusCode
当使用默认headers时(没有显式地调用 `response.writeHead()` 来修改headers),这个属性决定headers更新时被传回客户端的HTTP状态码。
实例:
~~~
response.statusCode = 404;
~~~
当响应头被发送回客户端,那么这个属性则表示已经被发送出去的状态码。
### response.setHeader(name, value)
为默认或者已存在的头设置一条单独的头内容。如果这个头已经存在于 将被送出的头中,将会覆盖原来的内容。如果我想设置更多的头, 就使用一个相同名字的字符串数组
实例:
~~~
response.setHeader("Content-Type", "text/html");
~~~
或者
~~~
response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);
~~~
### response.headersSent
布尔型值(只读).如果headers发送完毕,则为true,反之为false
### response.sendDate
若为true,则当headers里没有Date值时自动生成Date并发送.默认值为true
只有在测试环境才禁用它; 因为 HTTP 要求响应包含 `Date` 头.
### response.getHeader(name)
读取一个在队列中但是还没有被发送至客户端的header。需要注意的是 name 参数是不区分 大小写的。它只能在header还没被冲洗掉之前调用。
实例:
~~~
var contentType = response.getHeader('content-type');
~~~
### response.removeHeader(name)
取消掉一个在队列内等待发送的header。
实例:
~~~
response.removeHeader("Content-Encoding");
~~~
### response.write(chunk, [encoding])
如果这个方法被调用但是 `response.writeHead()` 没有被调用,它将切换到默认header模式并更新默认的headers。
它将发送一个响应体的数据块。这个方法可能被调用很多次以防止继承部分响应体。
`chunk`可以是字符串或者缓存。如果`chunk` 是一个字符串, 第二个参数表明如何将这个字符串编码为一个比特流。默认的 `encoding`是`'utf8'`。
**注意**: 这是底层的 HTTP 报文,高级的多部分报文编码无法使用。
当第一次 `response.write()` 被调用时,将会发送缓存的header信息和第一个报文给客户端。 第二次`response.write()`被调用时,Node假设你将发送数据流,然后分别地发送。这意味着响应 是缓存到第一次报文的数据块中。
如果所有数据被成功刷新到内核缓冲区,则返回`true`。如果所有或部分数据在用户内存里还处于队列中,则返回`false`。当缓冲区再次被释放时,`'drain'`事件会被分发。
### response.addTrailers(headers)
这个方法添加HTTP尾随headers(一个在消息末尾的header)给响应。
**只有** 当数据块编码被用于响应时尾随才会被触发。如果不是(例如,请求是HTTP/1.0 ),他们将会被自动丢弃。
需要注意的是如果要触发尾随消息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])
当所有的响应报头和报文被发送完成时这个方法将信号发送给服务器;服务器会认为这个消息完成了。 每次响应完成之后必须调用该方法。
如果指定了参数 `data` , 就相当于先调用 `response.write(data, encoding)` 之后再调用 `response.end()`.
### http.request(options, callback)
Node维护几个连接每个服务器的HTTP请求。 这个函数允许后台发布请求。
`options`可以是一个对象或一个字符串。如果`options`是一个字符串, 它将自动使用[url.parse()](#)解析。
Options:
- `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][]。
- `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`对象。
实例:
~~~
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
~~~
注意,例子里的`req.end()`被调用了。使用`http.request()`方法时都必须总是调用`req.end()`以表明这个请求已经完成,即使响应body里没有任何数据。
如果在请求期间发生错误(DNS解析、TCP级别的错误或实际HTTP解析错误
),在返回的请求对象会触发一个`'error'`事件。
有一些特殊的标题应该注意。
- 发送 'Connection: keep-alive'将会告知Node保持连接直到下一个请求发送。
- 发送 'Content-length' 头将会禁用默认的 chunked 编码.
- 发送 'Expect'报头会立即发送请求报头. 通常当发送 'Expect: 100-continue'时,你会同时发送一个超时和监听继续的事件。 查看 RFC2616 第 8.2.3 章节获得更多信息。
- 发送一个授权报头将会覆盖使用 `auth` 选项来完成基本授权。
### http.get(options, callback)
因为大部分的请求是没有报文体的GET请求,所以Node提供了这种便捷的方法。该方法与`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);
});
~~~
### Class: http.Agent
HTTP Agent 是用于把套接字做成资源池,用于HTTP客户端请求。
HTTP Agent 也把客户端的请求默认为使用Connection:keep-alive。如果没有HTTP请求正在等待成为空闲的套接字的话,那么套接字将关闭。这意味着Node的资源池在负载的情况下对keep-alive有利,但是仍然不需要开发人员使用KeepAlive来手动关闭HTTP客户端。
如果你选择使用HTTP KeepAlive,那么你可以创建一个标志设为`true`的Agent对象。(见下面的[构造函数选项](#)。)然后,Agent将会在资源池中保持未被使用的套接字,用于未来使用。它们将会被显式标记,以便于不保持Node进程的运行。但是当KeepAlive agent没有被使用时,显式地[`destroy()`](#) KeepAlive agent仍然是个好主意,这样套接字们会被关闭。
当套接字触发了close事件或者特殊的agentRemove事件的时候,套接字们从agent的资源池中移除。这意味着如果你打算保持一个HTTP请求长时间开启,并且不希望它保持在资源池中,那么你可以按照下列几行的代码做事:
~~~
http.get(options, function(res) {
// 做点事
}).on("socket", function (socket) {
socket.emit("agentRemove");
});
~~~