### 穩定度: 2 - 穩定
你必須通過`require('http')`來使用HTTP服務器和客戶端。
`io.js`中的HTTP接口被設置來支持許多HTTP協議里原本用起來很困難的特性。特別是大且成塊的有編碼的消息。這個接口從不緩沖整個請求或響應。用戶可以對它們使用流。
HTTP消息頭可能是一個類似于以下例子的對象:
~~~
{ 'content-length': '123',
'content-type': 'text/plain',
'connection': 'keep-alive',
'host': 'mysite.com',
'accept': '*/*' }
~~~
鍵是小寫的。值沒有被修改。
為了全方位的支持所有的HTTP應用。`io.js`的HTTP API是非常底層的。它只處理流以及解釋消息。它將消息解釋為消息頭和消息體,但是不解釋實際的消息頭和消息體。
被定義的消息頭允許以多個`,`字符分割,除了`set-cookie`和`cookie`頭,因為它們表示值得數組。如`content-length`這樣只有單個值的頭被直接將解析,并且成為解析后對象的一個單值。
收到的原始消息頭會被保留在`rawHeaders`屬性中,它是一個形式如`[key, value, key2, value2, ...]`的數組。例如,之前的消息頭可以有如下的`rawHeaders`:
~~~
[ 'ConTent-Length', '123456',
'content-LENGTH', '123',
'content-type', 'text/plain',
'CONNECTION', 'keep-alive',
'Host', 'mysite.com',
'accepT', '*/*' ]
~~~
#### http.METHODS
- Array
一個被解析器所支持的HTTP方法的列表。
#### http.STATUS_CODES
- Object
一個所有標準HTTP響應狀態碼的集合,以及它們的簡短描述。例如,`http.STATUS_CODES[404] === 'Not Found'`。
#### http.createServer([requestListener])
- 返回一個新的`http.Server`實例
`requestListener`是一個會被自動添加為`request`事件監聽器的函數。
#### http.createClient([port][, host])
這個函數已經被啟用。請使用`http.request()`替代。構造一個新的HTTP客戶端。`port`和`host`指定了需要連接的目標服務器。
#### Class: http.Server
這是一個具有以下事件的`EventEmitter`:
#### Event: 'request'
- function (request, response) { }
當有請求來到時觸發。注意每一個連接可能有多個請求(在長連接的情況下)。請求是一個`http.IncomingMessage`實例,響應是一個`http.ServerResponse`實例。
#### Event: 'connection'
- function (socket) { }
當一個新的TCP流建立時觸發。`socket`是一個`net.Socket`類型的實例。用戶通常不會接觸這個事件。特別的,因為協議解釋器綁定它的方式,`socket`將不會觸發`readable`事件。這個`socket`可以由`request.connection`得到。
#### Event: 'close'
- function () { }
當服務器關閉時觸發。
#### Event: 'checkContinue'
- function (request, response) { }
當每次收到一個HTTP`Expect: 100-continue`請求時觸發。如果不監聽這個事件,那么服務器會酌情自動響應一個`100 Continue`。
處理該事件時,如果客戶端可以繼續發送請求主體則調用`response.writeContinue()`, 如果不能則生成合適的HTTP響應(如`400 Bad Request`)。
注意,當這個事件被觸發并且被處理,`request`事件則不會再觸發。
#### Event: 'connect'
- function (request, socket, head) { }
每當客戶端發起一個http`CONNECT`請求時觸發。如果這個事件沒有被監聽,那么客戶端發起http`CONNECT`的連接會被關閉。
- `request`是一個http請求參數,它也被包含在`request`事件中。
- `socket`是一個服務器和客戶端間的網絡套接字。
- `head`是一個`Buffer`實例,隧道流中的第一個報文,該參數可能為空
在這個事件被觸發后,請求的`socket`將不會有`data`事件的監聽器,意味著你將要綁定一個`data`事件的監聽器來處理這個`socket`中發往服務器的數據。
#### Event: 'upgrade'
- function (request, socket, head) { }
每當客戶端發起一個http`upgrade`請求時觸發。如果這個事件沒有被監聽,那么客戶端發起`upgrade`的連接會被關閉。
- `request`是一個http請求參數,它也被包含在`request`事件中。
- `socket`是一個服務器和客戶端間的網絡套接字。
- `head`是一個`Buffer`實例,升級后流中的第一個報文,該參數可能為空
在這個事件被觸發后,請求的`socket`將不會有`data`事件的監聽器,意味著你將要綁定一個`data`事件的監聽器來處理這個`socket`中發往服務器的數據。
#### Event: 'clientError'
- function (exception, socket) { }
如果一個客戶端連接發生了錯誤,這個事件將會被觸發。
`socket`是一個錯誤來源的`net.Socket`對象。
#### server.listen(port[, hostname][, backlog][, callback])
從指定的端口和主機名開始接收連接。如果`hostname`被忽略,那么如果IPv6可用,服務器將接受任意IPv6地址(::),否則為任何IPv4地址(0.0.0.)。`port`為`0`將會設置一個隨機端口。
如果要監聽一個unix `socket`,請提供一個文件名而不是端口和主機名。
`backlog`是連接等待隊列的最大長度。它的實際長度將有你操作系統的`sysctl`設置(如linux中的`tcp_max_syn_backlog`和`somaxconn`)決定。默認值為`511`(不是`512`)。
這個函數式異步的。最后一個`callback`參數將會添加至`listening`事件的監聽器。參閱`net.Server.listen(port)`。
#### server.listen(path[, callback])
通過給定的`path`,開啟一個監聽連接的 UNIX `socket`服務器。
這個函數式異步的。最后一個`callback`參數將會添加至`listening`事件的監聽器。參閱`net.Server.listen(path)`。
#### server.listen(handle[, callback])
- handle Object
- callback Function
`handle`對象是既可以是一個server可以是一個`socket`(或者任意以下劃線開頭的成員`_handle`),或一個`{fd: <n>}`對象。
這將使得服務器使用指定句柄接受連接,但它假設文件描述符或句柄已經被綁定至指定的端口或域名`socket`。
在Windows下不支持監聽一個文件描述符。
這個函數式異步的。最后一個`callback`參數將會添加至`listening`事件的監聽器。參閱`net.Server.listen()`。
#### server.close([callback])
讓服務器停止接收新的連接。參閱`net.Server.close()`。
#### server.maxHeadersCount
限制最大請求頭數量,默認為`1000`。如果設置為`0`,則代表無限制。
#### server.setTimeout(msecs, callback)
- msecs Number
- callback Function
設置`socket`的超時值,并且如果超時,會在服務器對象上觸發一個`timeout`事件,并且將傳遞`socket`作為參數。
如果在服務器對象時又一個`timeout`事件監聽器,那么它將會被調用,而超時的`socket`將會被作為參數。
默認的,服務器的超時值是兩分鐘,并且如果超時,`socket`會被自動銷毀。但是,如果你給`timeout`事件傳遞了回調函數,那么你必須為要親自處理`socket`超時。
返回一個`server`對象。
#### server.timeout
- Number 默認為`120000`(兩分鐘)
一個`socket`被判定為超時之前的毫秒數。
注意,`socket`的超時邏輯在連接時被設定,所以改變它的值僅影響之后到達服務器的連接,而不是所有的連接。
設置為`0`將會為連接禁用所有的自動超時行為。
#### Class: http.ServerResponse
這個對象由HTTP服務器內部創建,而不是由用戶。它會被傳遞給`request`事件監聽器的第二個參數。
這個對象實現了`Writable`流接口。它是一個具有以下事件的`EventEmitter`:
#### Event: 'close'
- function () { }
表明底層的連接在`response.end()`被調用或能夠沖刷前被關閉。
#### Event: 'finish'
- function () { }
當響應被設置時觸發。更明確地說,這個事件在當響應頭的最后一段和響應體為了網絡傳輸而交給操作系統時觸發。它并不表明客戶端已經收到了任何信息。
這個事件之后,`response`對象不會再觸發任何事件。
#### response.writeContinue()
給客戶端傳遞一個`HTTP/1.1 100 Continue`信息,表明請求體必須被傳遞。參閱服務器的`checkContinue`事件。
#### response.writeHead(statusCode[, statusMessage][, headers])
為請求設置一個響應頭。`statusCode`是一個三位的HTTP狀態碼,如`404`。最后一個參數`headers`,是響應頭。第二個參數`statusMessage`是可選的,表示狀態碼的一個可讀信息。
例子:
~~~
var body = 'hello world';
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain' });
~~~
這個方法對于一個信息只能調用一次,并且它必須在`response.end()`之前被調用。
如果你在調用這個方法前調用了`response.write()`或`response.end()`,將會調用這個函數,并且一個`implicit/mutable`頭會被計算使用。
注意,`Content-Length`是以字節計,而不是以字符計。上面例子能正常運行時因為字符串`'hello world'`僅包含單字節字符。如果響應體包含了多字節編碼的字符,那么必須通過指定的編碼來調用`Buffer.byteLength()`來確定字節數。并且`io.js`不會檢查`Content-Length`與響應體的字節數是否相等。
#### response.setTimeout(msecs, callback)
- msecs Number
- callback Function
設置`socket`的超時值(毫秒),如果傳遞了回調函數,那么它將被添加至`response`對象的`timeout`事件的監聽器。
如果沒有為`request`,`request`或服務器添加`timeout`監聽器。那么`socket`會在超時時銷毀。如果你為`request`,`request`或服務器添加了`timeout`監聽器,那么你必須為要親自處理`socket`超時。
返回一個`response`對象。
#### response.statusCode
當使用隱式響應頭(不明確調用`response.writeHead()`)時,這個屬性控制了發送給客戶端的狀態碼,在當響應頭被沖刷時。
例子:
~~~
response.statusCode = 404;
~~~
在響應頭發送給客戶端之后,這個屬性表明了被發送的狀態碼。
#### response.statusMessage
當使用隱式響應頭(不明確調用`response.writeHead()`)時,這個屬性控制了發送給客戶端的狀態信息,在當響應頭被沖刷時。當它沒有被指定(`undefined`)時,將會使用標準HTTP狀態碼信息。
例子:
~~~
response.statusMessage = 'Not found';
~~~
在響應頭發送給客戶端之后,這個屬性表明了被發送的狀態信息。
#### response.setHeader(name, value)
為一個隱式的響應頭設置一個單獨的頭內容。如果這個頭已存在,那么將會被覆蓋。當你需要發送一個同名多值的頭內容時請使用一個字符串數組。
例子:
~~~
response.setHeader("Content-Type", "text/html");
//or
response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);
~~~
#### response.headersSent
布爾值(只讀)。如果響應頭被發送則為`true`,反之為`false`。
#### response.sendDate
當為`true`時,當響應頭中沒有`Date`值時會被自動設置。默認為`true`。
這個值只會為了測試目的才會被禁用。HTTP協議要求響應頭中有`Date`值。
#### response.getHeader(name)
讀取已經被排隊但還未發送給客戶端的響應頭。注意`name`是大小寫敏感的。這個函數只能在響應頭被隱式沖刷前被調用。
例子:
~~~
var contentType = response.getHeader('content-type');
~~~
#### response.removeHeader(name)
取消一個在隊列中等待隱式發送的頭。
例子:
~~~
response.removeHeader("Content-Encoding");
~~~
#### response.write(chunk[, encoding][, callback])
如果這個方法被調用并且`response.writeHead()`沒有備調用,那么它將轉換到隱式響應頭模式,并且刷新隱式響應頭。
這個方法傳遞一個數據塊的響應體。這個方法可能被調用多次來保證連續的提供響應體。
數據塊可以是一個字符串或一個`buffer`。如果數據塊是一個字符串,那么第二個參數是它的編碼。默認是UTF-8.最后一個回調函數參數會在數據塊被沖刷后觸發。注意:這是一個底層的HTTP報文,高級的多部分報文編碼無法使用。
第一次調用`response.write()`時,它會傳遞緩存的頭信息以及第一個報文給客戶端。第二次調用時,`io.js`假設你將發送數據流,然后分別發送。這意味著響應式緩沖到第一個報文的數據塊中。
如果整個數據都成功得沖刷至內核緩沖,則放回`true`。如果用戶內存中有部分或全部的數據在隊列中,那么返回`false`。`drain`事件將會在緩沖再次釋放時觸發。
#### response.addTrailers(headers)
這個方法添加HTTP尾隨頭(一個在消息最后的頭)給響應。
只有當數據編碼被用于響應時尾隨才會觸發。如果不是(如請求是`HTTP/1.0`),它們將被安靜地丟棄。
注意,如果你要觸發尾隨消息,HTTP要求傳遞一個包含報文頭場列表的尾隨頭:
~~~
response.writeHead(200, { 'Content-Type': 'text/plain',
'Trailer': 'Content-MD5' });
response.write(fileData);
response.addTrailers({'Content-MD5': "7895bf4b8828b55ceaf47747b4bca667"});
response.end();
~~~
#### response.end([data][, encoding][, callback])
這個方法告知服務器所有的響應頭和響應體都已經發送;服務器會認為這個消息完成了。這個方法必須在每次響應完成后被調用。
如果指定了`data`,就相當于調用了`response.write(data, encoding)`之后再調用`response.end(callback)`。
如果指定了回調函數,那么它將在響應流結束后觸發。
#### http.request(options[, callback])
`io.js`為每個服務器維護了幾個連接,用來產生HTTP請求。這函數允許你透明地發送請求。
`options`參數可以是一個對象或一個字符串,如果`options`是一個字符串,它將自動得被`url.parse()`翻譯。
**Options:**
- host: 一個將要向其發送請求的服務器域名或IP地址。默認為`localhost`。
- hostname: `host`的別名。為了支持`url.parse()`的話,`hostname`比`host`更好些。
- family: 解析`host`和`hostname`時的IP地址協議族。合法值是`4`和`6`。當沒有指定時,將都被使用。
- port: 遠程服務器端口。默認為`80`。
- localAddress: 用于綁定網絡連接的本地端口。
- socketPath: Unix域`socket`(使用`host:port`或`socketPath`)。
- method: 指定HTTP請求方法的字符串。默認為`GET`。
- path: 請求路徑。默認為`/`。如果有查詢字符串,則需要包含。例如'/index.html?page=12'。請求路徑包含非法字符時拋出異常。目前,只否決空格,不過在未來可能改變。
- headers: 一個包含請求頭的對象。
- auth: 用于計算認證頭的基本認證,即`'user:password'`。
- **agent**: 控制`agent`行為。當使用一個代理時,請求將默認為`Connection: keep-alive`。可能值有:
- undefined (默認): 在這個主機和端口上使用全局`agent。
- Agent object: 在`agent`中顯示使用passed。
- false: 跳出`agent`的連接池。默認請求為`Connection: close`。
可選的回調函數將會被添加為`response`事件的“一次性”監聽器(one time listener)。
`http.request()`返回一個`http.ClientRequest`類的實例。這個`ClientRequest`實例是一個可寫流。如果你需要使用`POST`請求上傳一個文件,那么就將之寫入這個`ClientRequest`對象。
例子:
~~~
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function() {
console.log('No more data in response.')
})
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write(postData);
req.end();
~~~
注意,在例子中調用了`req.end()`。使用`http.request()`時必須調用`req.end()`來表明你已經完成了請求(即使沒有數據要被寫入請求體)。
如果有一個錯誤在請求時發生(如DNS解析,TCP級別錯誤或實際的HTTP解析錯誤),一個`error`事件將會在返回對象上觸發。
下面有一些特殊的需要主要的請求頭:
-
發送`'Connection: keep-alive'`會告知`io.js`保持連直到下一個請求發送。
-
發送`'Content-length'`頭會禁用默認的數據塊編碼。
-
發送`'Expect'`頭將會立刻發送一個請求頭。通常,當發送`'Expect: 100-continue'`時,你需要同時設置一個超時和監聽后續的時間。參閱RFC2616的8.2.3章節來獲取更多信息。
-
發送一個授權頭將會覆蓋使用`auth`選項來進行基本授權。
#### http.get(options[, callback])
由于大多數請求是沒有請求體的`GET`請求。`io.js`提供了這個簡便的方法。這個方法和`http.request()`方法的唯一區別是它設置請求方法為`GET`且自動調用`req.end()`。
例子:
~~~
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response: " + res.statusCode);
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
~~~
#### Class: http.Agent
HTTP Agent是用來把HTTP客戶端請求中的`socket`做成池。
HTTP Agent 也把客戶端的請求默認為使用`Connection:keep-alive`。如果沒有HTTP請求正在等待成為空閑的套接字的話,那么套接字將關閉。這意味著`io.js`的資源池在負載的情況下對`keep-alive`有利,但是仍然不需要開發人員使用KeepAlive來手動關閉HTTP客戶端。
如果你選擇使用`HTTP KeepAlive`,那么你可以創建一個標志設為`true`的Agent對象(見下面的構造函數選項)。然后,Agent將會在資源池中保持未被使用的套接字,用于未來使用。它們將會被顯式標記,以便于不保持`io.js`進程的運行。但是當KeepAlive agent沒有被使用時,顯式地`destroy()` KeepAlive agent仍然是個好主意,這樣`socket`會被關閉。
當`socket`觸發了`close`事件或者特殊的`agentRemove`事件的時候,套接字們從agent的資源池中移除。這意味著如果你打算保持一個HTTP請求長時間開啟,并且不希望它保持在資源池中,那么你可以按照下列幾行的代碼做事:
~~~
http.get(options, function(res) {
// Do stuff
}).on("socket", function (socket) {
socket.emit("agentRemove");
});
~~~
另外,你可以使用`agent:false`來停用池:
~~~
http.get({
hostname: 'localhost',
port: 80,
path: '/',
agent: false // create a new agent just for this one request
}, function (res) {
// Do stuff with response
})
~~~
new Agent([options])#
**options Object 為agent設置可配置的選項。可以有以下屬性**:
- keepAlive Boolean 在未來保持池中的`socket`被其他請求所使用,默認為`false`
- keepAliveMsecs Integer 當使用HTTP KeepAlive時,通過被保持連接的`socket`發送TCP KeepAlive 報文的間隔。默認為`1000`。只在`KeepAlive`被設置為`true`時有效
- maxSockets Number 每個主機允許擁有的`socket`的最大數量。默認為`Infinity`
- maxFreeSockets Number 在空閑狀態下允許打開的最大`socket`數。僅在`keepAlive`為`true`時有效。默認為`256`
`http.request`使用的默認的`http.globalAgent`包含它們屬性的各自的默認值。
為了配置它們中的任何一個,你必須創建你自己的`Agent`對象。
~~~
var http = require('http');
var keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
http.request(options, onResponseCallback);
~~~
#### agent.maxSockets
默認為`Infinity`。決定了每個源上可以擁有的并發的`socket`的數量。源為`'host:port'`或`'host:port:localAddress'`結合體。
#### agent.maxFreeSockets
默認為`256`。對于支持HTTP KeepAlive的Agent,這設置了在空閑狀態下保持打開的最大`socket`數量。
#### agent.sockets
這個對象包含了正在被Agent使用de`socket`數組。請不要修改它。
#### agent.freeSockets
這個對象包含了當HTTP KeepAlive被使用時正在等待的`socket`數組。請不要修改它。
#### agent.requests
這個對象包含了還沒有被分配給`socket`的請求隊列。請不要修改它。
#### agent.destroy()
銷毀正在被agent使用的所有`socket`。
通常沒有必要這么做。但是,如果你正在使用一個啟用了`KeepAlive`的agent,那么最好明確地關閉agent當你知道它不會再被使用時。否則,在服務器關閉它們前`socket`可能被閑置。
#### agent.getName(options)
通過一個請求選項集合來獲取一個獨一無二的名字,來決定一個連接是否可被再使用。在http代理中,這返回`host:port:localAddress`。在https代理中,`name`包括了CA,cert,ciphers和`HTTPS/TLS-specific`配置來決定一個`socket`是否能被再使用。
#### http.globalAgent
所有的http客戶端請求使用的默認全局`Agent`實例。
#### Class: http.ClientRequest
這個對象時被內部創建的,并且通過`http.request()`被返回。它代表了一個正在處理的請求,其頭部已經進入了隊列。這個頭部仍然可以通過`setHeader(name, value)`,`getHeader(name)`和`removeHeader(name)`修改。實際的頭部會隨著第一個數據塊發送,或在關閉連接時發送。
要獲得響應對象,請為`response`事件添加一個監聽器。`request`對象的`response`事件將會在收到響應頭時觸發。這個`response`事件的第一個參數是一個`http.IncomingMessage`的實例。
在`response`事件期間,可以給響應對象添加監聽器;尤其是監聽`data`事件。
如果沒有添加`response`事件監聽器,那么響應會被完全忽略。但是,如果你添加了`response`事件,那么你必須通過調用`response.read()`,添加`data`事件監聽器或調用`.resume()`方法等等,來從響應對象中消耗數據。在數據被消費之前,`end`事件不會觸發。如果數據沒有被讀取,它會消耗內存,最后導致`'process out of memory'`錯誤。
注意:`io.js`不會檢查`Content-Length`和被傳輸的響應體長度是否相同。
這個請求實現了`Writable`流接口。這是一個包含了以下事件的`EventEmitter`:
#### Event: 'response'
- function (response) { }
當這個請求收到一個響應時觸發。這個事件只會被觸發一次。`response`參數是一個`http.IncomingMessage`實例。
- **Options:**
- host: 一個向其發送請求的服務器的域名或IP地址
- port: 遠程服務器的端口
- socketPath: Unix域`socket`(使用`host:port`或`socketPath`中的一個)
#### Event: 'socket'
- function (socket) { }
當一個`socket`被分配給一個請求時觸發。
#### Event: 'connect'
- function (response, socket, head) { }
每次服務器使用`CONNECT`方法響應一個請求時觸發。如果這個事件沒有被監聽,那么接受`CONNECT`方法的客戶端將會關閉它們的連接。
以下是一對客戶端/服務器代碼,展示如何監聽`connect`事件。
~~~
var http = require('http');
var net = require('net');
var url = require('url');
// Create an HTTP tunneling proxy
var proxy = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('okay');
});
proxy.on('connect', function(req, cltSocket, head) {
// connect to an origin server
var srvUrl = url.parse('http://' + req.url);
var srvSocket = net.connect(srvUrl.port, srvUrl.hostname, function() {
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: io.js-Proxy\r\n' +
'\r\n');
srvSocket.write(head);
srvSocket.pipe(cltSocket);
cltSocket.pipe(srvSocket);
});
});
// now that proxy is running
proxy.listen(1337, '127.0.0.1', function() {
// make a request to a tunneling proxy
var options = {
port: 1337,
hostname: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
};
var req = http.request(options);
req.end();
req.on('connect', function(res, socket, head) {
console.log('got connected!');
// make a request over an HTTP tunnel
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', function(chunk) {
console.log(chunk.toString());
});
socket.on('end', function() {
proxy.close();
});
});
});
~~~
#### Event: 'upgrade'
- function (response, socket, head) { }
Emitted each time a server responds to a request with an upgrade. If this event isn't being listened for, clients receiving an upgrade header will have their connections closed.每次服務器返回`upgrade`響應給請求時觸發。如果這個事件沒有被監聽,客戶端接收一個`upgrade`頭時會關閉它們的連接。
以下是一對客戶端/服務器代碼,展示如何監聽`upgrade`事件。
~~~
var http = require('http');
// Create an HTTP server
var srv = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('okay');
});
srv.on('upgrade', function(req, socket, head) {
socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n');
socket.pipe(socket); // echo back
});
// now that server is running
srv.listen(1337, '127.0.0.1', function() {
// make a request
var options = {
port: 1337,
hostname: '127.0.0.1',
headers: {
'Connection': 'Upgrade',
'Upgrade': 'websocket'
}
};
var req = http.request(options);
req.end();
req.on('upgrade', function(res, socket, upgradeHead) {
console.log('got upgraded!');
socket.end();
process.exit(0);
});
});
~~~
#### Event: 'continue'
- function () { }
當服務器發出一個`'100 Continue'`HTTP響應時,通常這是因為請求包含`'Expect: 100-continue'`。這是一個客戶端須要發送請求體的指示。
#### Event: 'abort'
- function () { }
當請求被客戶端中止時觸發。這個事件只會在第一次調用`abort()`時觸發。
#### request.flushHeaders()
沖刷請求頭。
由于效率原因,`io.js`通常在直到你調用`request.end()`或寫入第一個數據塊前都會緩沖請求頭,然后努力將請求頭和數據打包為一個TCP報文。
這通常是你想要的(它節約了一個TCP往返)。但當第一份數據會等待很久才被發送時不是。`request.flushHeaders()`使你能繞過這個優化并且啟動請求。
#### request.write(chunk[, encoding][, callback])
發送一個響應塊。當用戶想要將請求體流式得發送給服務器時,可以通過調用這個方法多次來辦到--在這種情況下,建議在創建請求時使用`['Transfer-Encoding', 'chunked']`頭。
`chunk`參數必須是一個`Buffer`或一個字符串。
`encoding`參數是可選的,并且僅當`chunk`是字符串時有效。默認為`'utf8'`。
`callback`參數是可選的,并且當數據塊被沖刷時被調用。
#### request.end([data][, encoding][, callback])
結束發送請求。如果有任何部分的請求體未被發送,這個函數將會將它們沖刷至流中。如果請求是成塊的,它會發送終結符`'0\r\n\r\n'`。
如果`data`被指定,那么這與調用`request.write(data, encoding)`后再調用`request.end(callback)`相同。
如果`callback`被指定,那么它將在請求流結束時被調用。
#### request.abort()
中止請求。
#### request.setTimeout(timeout[, callback])
一旦一個`socket`被分配給這個請求并且完成連接,`socket.setTimeout()`會被調用。
返回`request`對象。
#### request.setNoDelay([noDelay])
一旦一個`socket`被分配給這個請求并且完成連接,`socket.setNoDelay()`會被調用。
#### request.setSocketKeepAlive([enable][, initialDelay])
一旦一個`socket`被分配給這個請求并且完成連接,`socket.setKeepAlive()`會被調用。
#### http.IncomingMessage
一個`IncomingMessage`對象被`http.Server`或`http.ClientRequest`創建,并且分別被傳遞給`request`和`response`事件的第一個參數。它被用來取得響應狀態,響應頭和響應體。
它實現了`Readable`流接口,并且有以下額外的事件,方法和屬性。
#### Event: 'close'
- function () { }
表明底層連接被關閉。與`end`相同,這個時間每次響應只會觸發一次。
#### message.httpVersion
當向服務器發送請求時,客戶端發送的HTTP版本。向客戶端發送響應時,服務器響應的HTTP版本。通常是`'1.1'`或`'1.0'`。
另外,`response.httpVersionMajor`是第一個整數,`response.httpVersionMinor`是第二個整數。
#### message.headers
請求/響應頭對象。
只讀的頭名稱和值映射。頭名稱是小寫的,例子:
~~~
// Prints something like:
//
// { 'user-agent': 'curl/7.22.0',
// host: '127.0.0.1:8000',
// accept: '*/*' }
console.log(request.headers);
~~~
#### message.rawHeaders
接受到的原始請求/響應頭列表。
注意鍵和值在同一個列表中,它并非一個元組列表。于是,偶數偏移量為鍵,奇數偏移量為對應的值。
頭名稱不是必須小寫的,并且重復也沒有被合并。
~~~
// Prints something like:
//
// [ 'user-agent',
// 'this is invalid because there can be only one',
// 'User-Agent',
// 'curl/7.22.0',
// 'Host',
// '127.0.0.1:8000',
// 'ACCEPT',
// '*/*' ]
console.log(request.rawHeaders);
~~~
#### message.trailers
請求/響應尾部對象。只在`end`事件中存在。
#### message.rawTrailers
接受到的原始請求/響應頭尾部鍵值對。只在`end`事件中存在。
#### message.setTimeout(msecs, callback)
- msecs Number
- callback Function
調用`message.connection.setTimeout(msecs, callback)`。
返回`message`。
#### message.method
僅對從`http.Server`獲得的請求有效。
請求方法是字符串。只讀。例如:`'GET'`,`'DELETE'`。
#### message.url
僅對從`http.Server`獲得的請求有效。
請求的URL字符串。這僅僅只包含實際HTTP請求中的URL。如果請求是:
~~~
GET /status?name=ryan HTTP/1.1\r\n
Accept: text/plain\r\n
\r\n
~~~
那么`request.url`將是:
~~~
'/status?name=ryan'
~~~
如果你想分塊地解釋URL。你可以調用`require('url').parse(request.url)`。例子:
~~~
iojs> require('url').parse('/status?name=ryan')
{ href: '/status?name=ryan',
search: '?name=ryan',
query: 'name=ryan',
pathname: '/status' }
~~~
如果你想從查詢字符串中提取參數,你可以使用`require('querystring').parse`函數,或者給`require('url').parse`方法的第二個參數傳遞`true`,例子:
~~~
iojs> require('url').parse('/status?name=ryan', true)
{ href: '/status?name=ryan',
search: '?name=ryan',
query: { name: 'ryan' },
pathname: '/status' }
~~~
#### message.statusCode
只對從`http.ClientRequest`到來的響應有效。
3位整數HTTP狀態碼。如`404`。
#### message.statusMessage
只對從`http.ClientRequest`到來的響應有效。
HTTP響應狀態信息。如`OK`或`Internal Server Error`。
#### message.socket
與此連接關聯的`net.Socket`對象。
通過HTTPS的支持,使用`request.socket.getPeerCertificate()`來獲取客戶端的身份細節。