# HTTP
~~~
穩(wěn)定度: 3 - 穩(wěn)定
~~~
要使用HTTP服務(wù)器或客戶端功能,需引用此模塊`require('http')`.
Node中的HTTP接口的設(shè)計支持許多HTTP協(xié)議中原本用起來很困難的特性.特別是對于很大的或者塊編碼的消息.這些接口很謹慎,它從來不會完全緩存整個請求(request)或響應(yīng)(response),這樣用戶可以在請求(request)或響應(yīng)(response)中使用數(shù)據(jù)流.
HTTP 的消息頭(Headers)通過如下對象來表示:
~~~
{ 'content-length': '123',
'content-type': 'text/plain',
'connection': 'keep-alive',
'host': 'mysite.com',
'accept': '*/*' }
~~~
其中鍵為小寫字母,值是不能修改的。
為了能全面地支持可能的HTTP應(yīng)用程序,Node提供的HTTP API都很底層。它處理的只有流處理和消息解析。它把一份消息解析成報文頭和報文體,但是它不解析實際的報文頭和報文體。
定義好的消息頭允許多個值以`,`分割, 除了`set-cookie`和`cookie`,因為他們表示值的數(shù)組. 像 `content-length`這樣只能有單個值的消息頭直接解析, 并且只有單值可以表示成已解析好的對像.
接收到的原始頭信息以數(shù)組形式 `[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響應(yīng)狀態(tài)碼的集合和簡短描述。例如`http.STATUS_CODES[404] === 'Not Found'`。
### http.createServer([requestListener])
返回一個新的web服務(wù)器對象
參數(shù) `requestListener` 是一個函數(shù),它將會自動加入到 `'request'` 事件的監(jiān)聽隊列.
### http.createClient([port], [host])
該函數(shù)已**棄用**,請用[http.request()](#)代替. 創(chuàng)建一個新的HTTP客戶端. `port` 和`host` 表示所連接的服務(wù)器.
### Class: http.Server
這是一個包含下列事件的[EventEmitter](#):
### 事件 : 'request'
`function (request, response) { }`
每次收到一個請求時觸發(fā).注意每個連接又可能有多個請求(在`keep-alive`的連接中).`request`是`http.IncomingMessage`的一個實例.`response`是`http.ServerResponse`的一個實例
### 事件: 'connection'
`function (socket) { }`
新的TCP流建立時出發(fā)。 `socket`是一個`net.Socket`對象。 通常用戶無需處理該事件。 特別注意,協(xié)議解析器綁定套接字時采用的方式使套接字不會出發(fā)`readable`事件。 還可以通過`request.connection`訪問`socket`。
### 事件: 'close'
`function () { }`
當此服務(wù)器關(guān)閉時觸發(fā)
### Event: 'checkContinue'
`function (request, response) { }`
每當收到Expect: 100-continue的http請求時觸發(fā)。 如果未監(jiān)聽該事件,服務(wù)器會酌情自動發(fā)送100 Continue響應(yīng)。
處理該事件時,如果客戶端可以繼續(xù)發(fā)送請求主體則調(diào)用`response.writeContinue`, 如果不能則生成合適的HTTP響應(yīng)(例如,400 請求無效)。
需要注意到, 當這個事件觸發(fā)并且被處理后, `request` 事件將不再會觸發(fā).
### 事件: 'connect'
`function (request, socket, head) { }`
每當客戶端發(fā)起CONNECT請求時出發(fā)。如果未監(jiān)聽該事件,客戶端發(fā)起CONNECT請求時連接會被關(guān)閉。
- `request` 是該HTTP請求的參數(shù),與request事件中的相同。
- `socket` 是服務(wù)端與客戶端之間的網(wǎng)絡(luò)套接字。
- `head` 是一個Buffer實例,隧道流的第一個包,該參數(shù)可能為空。
在這個事件被分發(fā)后,請求的套接字將不會有`data`事件監(jiān)聽器,也就是說你將需要綁定一個監(jiān)聽器到`data`事件,來處理在套接字上被發(fā)送到服務(wù)器的數(shù)據(jù)。
### Event: 'upgrade'
`function (request, socket, head) { }`
每當一個客戶端請求http升級時,該事件被分發(fā)。如果這個事件沒有被監(jiān)聽,那么這些請求升級的客戶端的連接將會被關(guān)閉。
- `request` 是該HTTP請求的參數(shù),與request事件中的相同。
- `socket` 是服務(wù)端與客戶端之間的網(wǎng)絡(luò)套接字。
- `head` 是一個Buffer實例,升級后流的第一個包,該參數(shù)可能為空。
在這個事件被分發(fā)后,請求的套接字將不會有`data`事件監(jiān)聽器,也就是說你將需要綁定一個監(jiān)聽器到`data`事件,來處理在套接字上被發(fā)送到服務(wù)器的數(shù)據(jù)。
### Event: 'clientError'
`function (exception, socket) { }`
如果一個客戶端連接觸發(fā)了一個 'error' 事件, 它就會轉(zhuǎn)發(fā)到這里.
`socket` 是導致錯誤的 `net.Socket` 對象。
### server.listen(port, [hostname], [backlog], [callback])
開始在指定的主機名和端口接收連接。如果省略主機名,服務(wù)器會接收指向任意IPv4地址的鏈接(`INADDR_ANY`)。
監(jiān)聽一個 unix socket, 需要提供一個文件名而不是端口號和主機名。
積壓量 `backlog` 為連接等待隊列的最大長度。實際長度由您的操作系統(tǒng)通過 sysctl 設(shè)置決定,比如 Linux 上的 `tcp_max_syn_backlog` 和 `somaxconn`。該參數(shù)缺省值為 511(不是 512)。
這個函數(shù)是異步的。最后一個參數(shù)`callback`會被作為事件監(jiān)聽器添加到 ['listening'](#)事件。另見[net.Server.listen(port)](#)。
### server.listen(path, [callback])
啟動一個 UNIX 套接字服務(wù)器在所給路徑 `path` 上監(jiān)聽連接。
該函數(shù)是異步的.最后一個參數(shù)`callback`將會加入到[`listening`][]事件的監(jiān)聽隊列中.又見[net.Server.listen(path)](#).
### server.listen(handle, [callback])
- `handle`處理器 {Object}
- `callback`回調(diào)函數(shù) {Function}
`handle` 變量可以被設(shè)置為server 或者 socket(任一以下劃線開頭的成員 `_handle`), 或者一個 `{fd: <n>}` 對象
這將使服務(wù)器用指定的句柄接受連接,但它假設(shè)文件描述符或者句柄已經(jīng)被綁定在特定的端口或者域名套接字。
Windows 不支持監(jiān)聽一個文件描述符。
這個函數(shù)是異步的。最后一個參數(shù)`callback`會被作為事件監(jiān)聽器添加到['listening'](#)事件。另見[net.Server.listen()](#)。
### server.close([callback])
禁止服務(wù)端接收新的連接. 查看 [net.Server.close()](#).
### server.maxHeadersCount
最大請求頭數(shù)目限制, 默認 1000 個. 如果設(shè)置為0, 則代表不做任何限制.
### server.setTimeout(msecs, callback)
- `msecs` {Number}
- `callback` {Function}
為套接字設(shè)定超時值。如果一個超時發(fā)生,那么Server對象上會分發(fā)一個`'timeout'`事件,同時將套接字作為參數(shù)傳遞。
如果在Server對象上有一個`'timeout'`事件監(jiān)聽器,那么它將被調(diào)用,而超時的套接字會作為參數(shù)傳遞給這個監(jiān)聽器。
默認情況下,服務(wù)器的超時時間是2分鐘,超時后套接字會自動銷毀。 但是如果為‘timeout’事件指定了回調(diào)函數(shù),你需要負責處理套接字超時。
### server.timeout
- {Number} 默認 120000 (2 分鐘)
一個套接字被判斷為超時之前的閑置毫秒數(shù)。
注意套接字的超時邏輯在連接時被設(shè)定,所以更改這個值只會影響*新創(chuàng)建的*連接,而不會影響到現(xiàn)有連接。
設(shè)置為0將阻止之后建立的連接的一切自動超時行為。
### Class: http.ServerResponse
這是一個由HTTP服務(wù)器內(nèi)部創(chuàng)建的對象(不是由用戶自行創(chuàng)建)。它將作為第二個參數(shù)傳遞到`'request'`事件中。
該響應(yīng)實現(xiàn)了 [Writable Stream](#) 接口。這是一個包含下列事件的 [EventEmitter](#) :
### 事件: 'close'
`function () { }`
需要注意的是,底層鏈接在`response.end()`被調(diào)用或可以沖洗掉之前就被終結(jié)了。
### response.writeContinue()
發(fā)送一個 HTTP/1.1 100 Continue 消息至客戶端,表明請求體可以被發(fā)送??梢栽俜?wù)器上查看['checkContinue'](#)事件。
### response.writeHead(statusCode, [reasonPhrase], [headers])
向請求回復響應(yīng)頭. statusCode是一個三位是的HTTP狀態(tài)碼, 例如 `404`. 最后一個參數(shù), `headers`, 是響應(yīng)頭的內(nèi)容. 可以選擇性的,把人類可讀的‘原因短句’作為第二個參數(shù)。
實例:
~~~
var body = 'hello world';
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
~~~
這個方法只能在當前請求中使用一次,并且必須在`response.end()`之前調(diào)用。
如果你在調(diào)用這之前調(diào)用了`response.write()`或者 `response.end()` , 就會調(diào)用這個函數(shù),并且 不明/容易混淆 的頭將會被使用。
注意:Content-Length 是以字節(jié)(byte)計,而不是以字符(character)計。之前的例子奏效的原因是字符串'hello world'只包含了單字節(jié)的字符。如果body包含了多字節(jié)編碼的字符,就應(yīng)當使用Buffer.byteLength()來確定在多字節(jié)字符編碼情況下字符串的字節(jié)數(shù)。需要進一步說明的是Node不檢查Content-Lenth屬性和已傳輸?shù)腷ody長度是否吻合。
### response.setTimeout(msecs, callback)
- `msecs` {Number}
- `callback` {Function}
設(shè)定套接字的超時時間為`msecs`。如果提供了回調(diào)函數(shù),會將其添加為響應(yīng)對象的`'timeout'`事件的監(jiān)聽器。
如果請求、響應(yīng)、服務(wù)器均未添加`'timeout'`事件監(jiān)聽,套接字將在超時時被銷毀。 如果監(jiān)聽了請求、響應(yīng)、服務(wù)器之一的`'timeout'`事件,需要自行處理超時的套接字。
### response.statusCode
當使用默認headers時(沒有顯式地調(diào)用 `response.writeHead()` 來修改headers),這個屬性決定headers更新時被傳回客戶端的HTTP狀態(tài)碼。
實例:
~~~
response.statusCode = 404;
~~~
當響應(yīng)頭被發(fā)送回客戶端,那么這個屬性則表示已經(jīng)被發(fā)送出去的狀態(tài)碼。
### response.setHeader(name, value)
為默認或者已存在的頭設(shè)置一條單獨的頭內(nèi)容。如果這個頭已經(jīng)存在于 將被送出的頭中,將會覆蓋原來的內(nèi)容。如果我想設(shè)置更多的頭, 就使用一個相同名字的字符串數(shù)組
實例:
~~~
response.setHeader("Content-Type", "text/html");
~~~
或者
~~~
response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);
~~~
### response.headersSent
布爾型值(只讀).如果headers發(fā)送完畢,則為true,反之為false
### response.sendDate
若為true,則當headers里沒有Date值時自動生成Date并發(fā)送.默認值為true
只有在測試環(huán)境才禁用它; 因為 HTTP 要求響應(yīng)包含 `Date` 頭.
### response.getHeader(name)
讀取一個在隊列中但是還沒有被發(fā)送至客戶端的header。需要注意的是 name 參數(shù)是不區(qū)分 大小寫的。它只能在header還沒被沖洗掉之前調(diào)用。
實例:
~~~
var contentType = response.getHeader('content-type');
~~~
### response.removeHeader(name)
取消掉一個在隊列內(nèi)等待發(fā)送的header。
實例:
~~~
response.removeHeader("Content-Encoding");
~~~
### response.write(chunk, [encoding])
如果這個方法被調(diào)用但是 `response.writeHead()` 沒有被調(diào)用,它將切換到默認header模式并更新默認的headers。
它將發(fā)送一個響應(yīng)體的數(shù)據(jù)塊。這個方法可能被調(diào)用很多次以防止繼承部分響應(yīng)體。
`chunk`可以是字符串或者緩存。如果`chunk` 是一個字符串, 第二個參數(shù)表明如何將這個字符串編碼為一個比特流。默認的 `encoding`是`'utf8'`。
**注意**: 這是底層的 HTTP 報文,高級的多部分報文編碼無法使用。
當?shù)谝淮?`response.write()` 被調(diào)用時,將會發(fā)送緩存的header信息和第一個報文給客戶端。 第二次`response.write()`被調(diào)用時,Node假設(shè)你將發(fā)送數(shù)據(jù)流,然后分別地發(fā)送。這意味著響應(yīng) 是緩存到第一次報文的數(shù)據(jù)塊中。
如果所有數(shù)據(jù)被成功刷新到內(nèi)核緩沖區(qū),則返回`true`。如果所有或部分數(shù)據(jù)在用戶內(nèi)存里還處于隊列中,則返回`false`。當緩沖區(qū)再次被釋放時,`'drain'`事件會被分發(fā)。
### response.addTrailers(headers)
這個方法添加HTTP尾隨headers(一個在消息末尾的header)給響應(yīng)。
**只有** 當數(shù)據(jù)塊編碼被用于響應(yīng)時尾隨才會被觸發(fā)。如果不是(例如,請求是HTTP/1.0 ),他們將會被自動丟棄。
需要注意的是如果要觸發(fā)尾隨消息HTTP要求一個報文頭場列表和`Trailer`報頭一起發(fā)送,例如:
~~~
response.writeHead(200, { 'Content-Type': 'text/plain',
'Trailer': 'Content-MD5' });
response.write(fileData);
response.addTrailers({'Content-MD5': "7895bf4b8828b55ceaf47747b4bca667"});
response.end();
~~~
### response.end([data], [encoding])
當所有的響應(yīng)報頭和報文被發(fā)送完成時這個方法將信號發(fā)送給服務(wù)器;服務(wù)器會認為這個消息完成了。 每次響應(yīng)完成之后必須調(diào)用該方法。
如果指定了參數(shù) `data` , 就相當于先調(diào)用 `response.write(data, encoding)` 之后再調(diào)用 `response.end()`.
### http.request(options, callback)
Node維護幾個連接每個服務(wù)器的HTTP請求。 這個函數(shù)允許后臺發(fā)布請求。
`options`可以是一個對象或一個字符串。如果`options`是一個字符串, 它將自動使用[url.parse()](#)解析。
Options:
- `host`:請求發(fā)送到的服務(wù)器的域名或IP地址。默認為`'localhost'`。
- `hostname`:用于支持`url.parse()`。`hostname`比`host`更好一些
- `port`:遠程服務(wù)器的端口。默認值為80。
- `localAddress`:用于綁定網(wǎng)絡(luò)連接的本地接口。
- `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的時候,通過正在保持活動的套接字發(fā)送TCP KeepAlive包的頻繁程度。默認值為`1000`。僅當`keepAlive`被設(shè)置為`true`時才相關(guān)。
`http.request()` 返回一個 `http.ClientRequest`類的實例。`ClientRequest`實例是一個可寫流對象。如果需要用POST請求上傳一個文件的話,就將其寫入到`ClientRequest`對象。
實例:
~~~
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
~~~
注意,例子里的`req.end()`被調(diào)用了。使用`http.request()`方法時都必須總是調(diào)用`req.end()`以表明這個請求已經(jīng)完成,即使響應(yīng)body里沒有任何數(shù)據(jù)。
如果在請求期間發(fā)生錯誤(DNS解析、TCP級別的錯誤或?qū)嶋HHTTP解析錯誤
),在返回的請求對象會觸發(fā)一個`'error'`事件。
有一些特殊的標題應(yīng)該注意。
- 發(fā)送 'Connection: keep-alive'將會告知Node保持連接直到下一個請求發(fā)送。
- 發(fā)送 'Content-length' 頭將會禁用默認的 chunked 編碼.
- 發(fā)送 'Expect'報頭會立即發(fā)送請求報頭. 通常當發(fā)送 'Expect: 100-continue'時,你會同時發(fā)送一個超時和監(jiān)聽繼續(xù)的事件。 查看 RFC2616 第 8.2.3 章節(jié)獲得更多信息。
- 發(fā)送一個授權(quán)報頭將會覆蓋使用 `auth` 選項來完成基本授權(quán)。
### http.get(options, callback)
因為大部分的請求是沒有報文體的GET請求,所以Node提供了這種便捷的方法。該方法與`http.request()`的唯一區(qū)別是它設(shè)置的是GET方法并自動調(diào)用`req.end()`。
實例:
~~~
http.get("http://www.google.com/index.html", function(res) {
console.log("響應(yīng):" + res.statusCode);
}).on('error', function(e) {
console.log("錯誤:" + e.message);
});
~~~
### Class: http.Agent
HTTP Agent 是用于把套接字做成資源池,用于HTTP客戶端請求。
HTTP Agent 也把客戶端的請求默認為使用Connection:keep-alive。如果沒有HTTP請求正在等待成為空閑的套接字的話,那么套接字將關(guān)閉。這意味著Node的資源池在負載的情況下對keep-alive有利,但是仍然不需要開發(fā)人員使用KeepAlive來手動關(guān)閉HTTP客戶端。
如果你選擇使用HTTP KeepAlive,那么你可以創(chuàng)建一個標志設(shè)為`true`的Agent對象。(見下面的[構(gòu)造函數(shù)選項](#)。)然后,Agent將會在資源池中保持未被使用的套接字,用于未來使用。它們將會被顯式標記,以便于不保持Node進程的運行。但是當KeepAlive agent沒有被使用時,顯式地[`destroy()`](#) KeepAlive agent仍然是個好主意,這樣套接字們會被關(guān)閉。
當套接字觸發(fā)了close事件或者特殊的agentRemove事件的時候,套接字們從agent的資源池中移除。這意味著如果你打算保持一個HTTP請求長時間開啟,并且不希望它保持在資源池中,那么你可以按照下列幾行的代碼做事:
~~~
http.get(options, function(res) {
// 做點事
}).on("socket", function (socket) {
socket.emit("agentRemove");
});
~~~
