# 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");
});
~~~