IO.js HTTP

2018-11-28 22:34 更新

穩(wěn)定度: 2 - 穩(wěn)定

你必須通過(guò)require('http')來(lái)使用HTTP服務(wù)器和客戶(hù)端。

io.js中的HTTP接口被設(shè)置來(lái)支持許多HTTP協(xié)議里原本用起來(lái)很困難的特性。特別是大且成塊的有編碼的消息。這個(gè)接口從不緩沖整個(gè)請(qǐng)求或響應(yīng)。用戶(hù)可以對(duì)它們使用流。

HTTP消息頭可能是一個(gè)類(lèi)似于以下例子的對(duì)象:

{ 'content-length': '123',
  'content-type': 'text/plain',
  'connection': 'keep-alive',
  'host': 'mysite.com',
  'accept': '*/*' }

鍵是小寫(xiě)的。值沒(méi)有被修改。

為了全方位的支持所有的HTTP應(yīng)用。io.js的HTTP API是非常底層的。它只處理流以及解釋消息。它將消息解釋為消息頭和消息體,但是不解釋實(shí)際的消息頭和消息體。

被定義的消息頭允許以多個(gè),字符分割,除了set-cookiecookie頭,因?yàn)樗鼈儽硎局档脭?shù)組。如content-length這樣只有單個(gè)值的頭被直接將解析,并且成為解析后對(duì)象的一個(gè)單值。

收到的原始消息頭會(huì)被保留在rawHeaders屬性中,它是一個(gè)形式如[key, value, key2, value2, ...]的數(shù)組。例如,之前的消息頭可以有如下的rawHeaders

[ 'ConTent-Length', '123456',
  'content-LENGTH', '123',
  'content-type', 'text/plain',
  'CONNECTION', 'keep-alive',
  'Host', 'mysite.com',
  'accepT', '*/*' ]

http.METHODS

  • Array

一個(gè)被解析器所支持的HTTP方法的列表。

http.STATUS_CODES

  • Object

一個(gè)所有標(biāo)準(zhǔn)HTTP響應(yīng)狀態(tài)碼的集合,以及它們的簡(jiǎn)短描述。例如,http.STATUS_CODES[404] === 'Not Found'。

http.createServer([requestListener])

  • 返回一個(gè)新的http.Server實(shí)例

requestListener是一個(gè)會(huì)被自動(dòng)添加為request事件監(jiān)聽(tīng)器的函數(shù)。

http.createClient([port][, host])

這個(gè)函數(shù)已經(jīng)被啟用。請(qǐng)使用http.request()替代。構(gòu)造一個(gè)新的HTTP客戶(hù)端。porthost指定了需要連接的目標(biāo)服務(wù)器。

Class: http.Server

這是一個(gè)具有以下事件的EventEmitter

Event: 'request'

  • function (request, response) { }

當(dāng)有請(qǐng)求來(lái)到時(shí)觸發(fā)。注意每一個(gè)連接可能有多個(gè)請(qǐng)求(在長(zhǎng)連接的情況下)。請(qǐng)求是一個(gè)http.IncomingMessage實(shí)例,響應(yīng)是一個(gè)http.ServerResponse實(shí)例。

Event: 'connection'

  • function (socket) { }

當(dāng)一個(gè)新的TCP流建立時(shí)觸發(fā)。socket是一個(gè)net.Socket類(lèi)型的實(shí)例。用戶(hù)通常不會(huì)接觸這個(gè)事件。特別的,因?yàn)閰f(xié)議解釋器綁定它的方式,socket將不會(huì)觸發(fā)readable事件。這個(gè)socket可以由request.connection得到。

Event: 'close'

  • function () { }

當(dāng)服務(wù)器關(guān)閉時(shí)觸發(fā)。

Event: 'checkContinue'

  • function (request, response) { }

當(dāng)每次收到一個(gè)HTTPExpect: 100-continue請(qǐng)求時(shí)觸發(fā)。如果不監(jiān)聽(tīng)這個(gè)事件,那么服務(wù)器會(huì)酌情自動(dòng)響應(yīng)一個(gè)100 Continue。

處理該事件時(shí),如果客戶(hù)端可以繼續(xù)發(fā)送請(qǐng)求主體則調(diào)用response.writeContinue(), 如果不能則生成合適的HTTP響應(yīng)(如400 Bad Request)。

注意,當(dāng)這個(gè)事件被觸發(fā)并且被處理,request事件則不會(huì)再觸發(fā)。

Event: 'connect'

  • function (request, socket, head) { }

每當(dāng)客戶(hù)端發(fā)起一個(gè)httpCONNECT請(qǐng)求時(shí)觸發(fā)。如果這個(gè)事件沒(méi)有被監(jiān)聽(tīng),那么客戶(hù)端發(fā)起httpCONNECT的連接會(huì)被關(guān)閉。

  • request是一個(gè)http請(qǐng)求參數(shù),它也被包含在request事件中。
  • socket是一個(gè)服務(wù)器和客戶(hù)端間的網(wǎng)絡(luò)套接字。
  • head是一個(gè)Buffer實(shí)例,隧道流中的第一個(gè)報(bào)文,該參數(shù)可能為空

在這個(gè)事件被觸發(fā)后,請(qǐng)求的socket將不會(huì)有data事件的監(jiān)聽(tīng)器,意味著你將要綁定一個(gè)data事件的監(jiān)聽(tīng)器來(lái)處理這個(gè)socket中發(fā)往服務(wù)器的數(shù)據(jù)。

Event: 'upgrade'

  • function (request, socket, head) { }

每當(dāng)客戶(hù)端發(fā)起一個(gè)httpupgrade請(qǐng)求時(shí)觸發(fā)。如果這個(gè)事件沒(méi)有被監(jiān)聽(tīng),那么客戶(hù)端發(fā)起upgrade的連接會(huì)被關(guān)閉。

  • request是一個(gè)http請(qǐng)求參數(shù),它也被包含在request事件中。
  • socket是一個(gè)服務(wù)器和客戶(hù)端間的網(wǎng)絡(luò)套接字。
  • head是一個(gè)Buffer實(shí)例,升級(jí)后流中的第一個(gè)報(bào)文,該參數(shù)可能為空

在這個(gè)事件被觸發(fā)后,請(qǐng)求的socket將不會(huì)有data事件的監(jiān)聽(tīng)器,意味著你將要綁定一個(gè)data事件的監(jiān)聽(tīng)器來(lái)處理這個(gè)socket中發(fā)往服務(wù)器的數(shù)據(jù)。

Event: 'clientError'

  • function (exception, socket) { }

如果一個(gè)客戶(hù)端連接發(fā)生了錯(cuò)誤,這個(gè)事件將會(huì)被觸發(fā)。

socket是一個(gè)錯(cuò)誤來(lái)源的net.Socket對(duì)象。

server.listen(port[, hostname][, backlog][, callback])

從指定的端口和主機(jī)名開(kāi)始接收連接。如果hostname被忽略,那么如果IPv6可用,服務(wù)器將接受任意IPv6地址(::),否則為任何IPv4地址(0.0.0.)。port0將會(huì)設(shè)置一個(gè)隨機(jī)端口。

如果要監(jiān)聽(tīng)一個(gè)unix socket,請(qǐng)?zhí)峁┮粋€(gè)文件名而不是端口和主機(jī)名。

backlog是連接等待隊(duì)列的最大長(zhǎng)度。它的實(shí)際長(zhǎng)度將有你操作系統(tǒng)的sysctl設(shè)置(如linux中的tcp_max_syn_backlogsomaxconn)決定。默認(rèn)值為511(不是512)。

這個(gè)函數(shù)式異步的。最后一個(gè)callback參數(shù)將會(huì)添加至listening事件的監(jiān)聽(tīng)器。參閱net.Server.listen(port)。

server.listen(path[, callback])

通過(guò)給定的path,開(kāi)啟一個(gè)監(jiān)聽(tīng)連接的 UNIX socket服務(wù)器。

這個(gè)函數(shù)式異步的。最后一個(gè)callback參數(shù)將會(huì)添加至listening事件的監(jiān)聽(tīng)器。參閱net.Server.listen(path)。

server.listen(handle[, callback])

  • handle Object
  • callback Function

handle對(duì)象是既可以是一個(gè)server可以是一個(gè)socket(或者任意以下劃線開(kāi)頭的成員_handle),或一個(gè){fd: <n>}對(duì)象。

這將使得服務(wù)器使用指定句柄接受連接,但它假設(shè)文件描述符或句柄已經(jīng)被綁定至指定的端口或域名socket。

在Windows下不支持監(jiān)聽(tīng)一個(gè)文件描述符。

這個(gè)函數(shù)式異步的。最后一個(gè)callback參數(shù)將會(huì)添加至listening事件的監(jiān)聽(tīng)器。參閱net.Server.listen()。

server.close([callback])

讓服務(wù)器停止接收新的連接。參閱net.Server.close()。

server.maxHeadersCount

限制最大請(qǐng)求頭數(shù)量,默認(rèn)為1000。如果設(shè)置為0,則代表無(wú)限制。

server.setTimeout(msecs, callback)

  • msecs Number
  • callback Function

設(shè)置socket的超時(shí)值,并且如果超時(shí),會(huì)在服務(wù)器對(duì)象上觸發(fā)一個(gè)timeout事件,并且將傳遞socket作為參數(shù)。

如果在服務(wù)器對(duì)象時(shí)又一個(gè)timeout事件監(jiān)聽(tīng)器,那么它將會(huì)被調(diào)用,而超時(shí)的socket將會(huì)被作為參數(shù)。

默認(rèn)的,服務(wù)器的超時(shí)值是兩分鐘,并且如果超時(shí),socket會(huì)被自動(dòng)銷(xiāo)毀。但是,如果你給timeout事件傳遞了回調(diào)函數(shù),那么你必須為要親自處理socket超時(shí)。

返回一個(gè)server對(duì)象。

server.timeout

  • Number 默認(rèn)為120000(兩分鐘)

一個(gè)socket被判定為超時(shí)之前的毫秒數(shù)。

注意,socket的超時(shí)邏輯在連接時(shí)被設(shè)定,所以改變它的值僅影響之后到達(dá)服務(wù)器的連接,而不是所有的連接。

設(shè)置為0將會(huì)為連接禁用所有的自動(dòng)超時(shí)行為。

Class: http.ServerResponse

這個(gè)對(duì)象由HTTP服務(wù)器內(nèi)部創(chuàng)建,而不是由用戶(hù)。它會(huì)被傳遞給request事件監(jiān)聽(tīng)器的第二個(gè)參數(shù)。

這個(gè)對(duì)象實(shí)現(xiàn)了Writable流接口。它是一個(gè)具有以下事件的EventEmitter

Event: 'close'

  • function () { }

表明底層的連接在response.end()被調(diào)用或能夠沖刷前被關(guān)閉。

Event: 'finish'

  • function () { }

當(dāng)響應(yīng)被設(shè)置時(shí)觸發(fā)。更明確地說(shuō),這個(gè)事件在當(dāng)響應(yīng)頭的最后一段和響應(yīng)體為了網(wǎng)絡(luò)傳輸而交給操作系統(tǒng)時(shí)觸發(fā)。它并不表明客戶(hù)端已經(jīng)收到了任何信息。

這個(gè)事件之后,response對(duì)象不會(huì)再觸發(fā)任何事件。

response.writeContinue()

給客戶(hù)端傳遞一個(gè)HTTP/1.1 100 Continue信息,表明請(qǐng)求體必須被傳遞。參閱服務(wù)器的checkContinue事件。

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

為請(qǐng)求設(shè)置一個(gè)響應(yīng)頭。statusCode是一個(gè)三位的HTTP狀態(tài)碼,如404。最后一個(gè)參數(shù)headers,是響應(yīng)頭。第二個(gè)參數(shù)statusMessage是可選的,表示狀態(tài)碼的一個(gè)可讀信息。

例子:

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

這個(gè)方法對(duì)于一個(gè)信息只能調(diào)用一次,并且它必須在response.end()之前被調(diào)用。

如果你在調(diào)用這個(gè)方法前調(diào)用了response.write()response.end(),將會(huì)調(diào)用這個(gè)函數(shù),并且一個(gè)implicit/mutable頭會(huì)被計(jì)算使用。

注意,Content-Length是以字節(jié)計(jì),而不是以字符計(jì)。上面例子能正常運(yùn)行時(shí)因?yàn)樽址?code>'hello world'僅包含單字節(jié)字符。如果響應(yīng)體包含了多字節(jié)編碼的字符,那么必須通過(guò)指定的編碼來(lái)調(diào)用Buffer.byteLength()來(lái)確定字節(jié)數(shù)。并且io.js不會(huì)檢查Content-Length與響應(yīng)體的字節(jié)數(shù)是否相等。

response.setTimeout(msecs, callback)

  • msecs Number
  • callback Function

設(shè)置socket的超時(shí)值(毫秒),如果傳遞了回調(diào)函數(shù),那么它將被添加至response對(duì)象的timeout事件的監(jiān)聽(tīng)器。

如果沒(méi)有為requestrequest或服務(wù)器添加timeout監(jiān)聽(tīng)器。那么socket會(huì)在超時(shí)時(shí)銷(xiāo)毀。如果你為request,request或服務(wù)器添加了timeout監(jiān)聽(tīng)器,那么你必須為要親自處理socket超時(shí)。

返回一個(gè)response對(duì)象。

response.statusCode

當(dāng)使用隱式響應(yīng)頭(不明確調(diào)用response.writeHead())時(shí),這個(gè)屬性控制了發(fā)送給客戶(hù)端的狀態(tài)碼,在當(dāng)響應(yīng)頭被沖刷時(shí)。

例子:

response.statusCode = 404;

在響應(yīng)頭發(fā)送給客戶(hù)端之后,這個(gè)屬性表明了被發(fā)送的狀態(tài)碼。

response.statusMessage

當(dāng)使用隱式響應(yīng)頭(不明確調(diào)用response.writeHead())時(shí),這個(gè)屬性控制了發(fā)送給客戶(hù)端的狀態(tài)信息,在當(dāng)響應(yīng)頭被沖刷時(shí)。當(dāng)它沒(méi)有被指定(undefined)時(shí),將會(huì)使用標(biāo)準(zhǔn)HTTP狀態(tài)碼信息。

例子:

response.statusMessage = 'Not found';

在響應(yīng)頭發(fā)送給客戶(hù)端之后,這個(gè)屬性表明了被發(fā)送的狀態(tài)信息。

response.setHeader(name, value)

為一個(gè)隱式的響應(yīng)頭設(shè)置一個(gè)單獨(dú)的頭內(nèi)容。如果這個(gè)頭已存在,那么將會(huì)被覆蓋。當(dāng)你需要發(fā)送一個(gè)同名多值的頭內(nèi)容時(shí)請(qǐng)使用一個(gè)字符串?dāng)?shù)組。

例子:

response.setHeader("Content-Type", "text/html");
//or

response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);

response.headersSent

布爾值(只讀)。如果響應(yīng)頭被發(fā)送則為true,反之為false。

response.sendDate

當(dāng)為true時(shí),當(dāng)響應(yīng)頭中沒(méi)有Date值時(shí)會(huì)被自動(dòng)設(shè)置。默認(rèn)為true。

這個(gè)值只會(huì)為了測(cè)試目的才會(huì)被禁用。HTTP協(xié)議要求響應(yīng)頭中有Date值。

response.getHeader(name)

讀取已經(jīng)被排隊(duì)但還未發(fā)送給客戶(hù)端的響應(yīng)頭。注意name是大小寫(xiě)敏感的。這個(gè)函數(shù)只能在響應(yīng)頭被隱式?jīng)_刷前被調(diào)用。

例子:

var contentType = response.getHeader('content-type');

response.removeHeader(name)

取消一個(gè)在隊(duì)列中等待隱式發(fā)送的頭。

例子:

response.removeHeader("Content-Encoding");

response.write(chunk[, encoding][, callback])

如果這個(gè)方法被調(diào)用并且response.writeHead()沒(méi)有備調(diào)用,那么它將轉(zhuǎn)換到隱式響應(yīng)頭模式,并且刷新隱式響應(yīng)頭。

這個(gè)方法傳遞一個(gè)數(shù)據(jù)塊的響應(yīng)體。這個(gè)方法可能被調(diào)用多次來(lái)保證連續(xù)的提供響應(yīng)體。

數(shù)據(jù)塊可以是一個(gè)字符串或一個(gè)buffer。如果數(shù)據(jù)塊是一個(gè)字符串,那么第二個(gè)參數(shù)是它的編碼。默認(rèn)是UTF-8.最后一個(gè)回調(diào)函數(shù)參數(shù)會(huì)在數(shù)據(jù)塊被沖刷后觸發(fā)。注意:這是一個(gè)底層的HTTP報(bào)文,高級(jí)的多部分報(bào)文編碼無(wú)法使用。

第一次調(diào)用response.write()時(shí),它會(huì)傳遞緩存的頭信息以及第一個(gè)報(bào)文給客戶(hù)端。第二次調(diào)用時(shí),io.js假設(shè)你將發(fā)送數(shù)據(jù)流,然后分別發(fā)送。這意味著響應(yīng)式緩沖到第一個(gè)報(bào)文的數(shù)據(jù)塊中。

如果整個(gè)數(shù)據(jù)都成功得沖刷至內(nèi)核緩沖,則放回true。如果用戶(hù)內(nèi)存中有部分或全部的數(shù)據(jù)在隊(duì)列中,那么返回false。drain事件將會(huì)在緩沖再次釋放時(shí)觸發(fā)。

response.addTrailers(headers)

這個(gè)方法添加HTTP尾隨頭(一個(gè)在消息最后的頭)給響應(yīng)。

只有當(dāng)數(shù)據(jù)編碼被用于響應(yīng)時(shí)尾隨才會(huì)觸發(fā)。如果不是(如請(qǐng)求是HTTP/1.0),它們將被安靜地丟棄。

注意,如果你要觸發(fā)尾隨消息,HTTP要求傳遞一個(gè)包含報(bào)文頭場(chǎng)列表的尾隨頭:

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])

這個(gè)方法告知服務(wù)器所有的響應(yīng)頭和響應(yīng)體都已經(jīng)發(fā)送;服務(wù)器會(huì)認(rèn)為這個(gè)消息完成了。這個(gè)方法必須在每次響應(yīng)完成后被調(diào)用。

如果指定了data,就相當(dāng)于調(diào)用了response.write(data, encoding)之后再調(diào)用response.end(callback)

如果指定了回調(diào)函數(shù),那么它將在響應(yīng)流結(jié)束后觸發(fā)。

http.request(options[, callback])

io.js為每個(gè)服務(wù)器維護(hù)了幾個(gè)連接,用來(lái)產(chǎn)生HTTP請(qǐng)求。這函數(shù)允許你透明地發(fā)送請(qǐng)求。

options參數(shù)可以是一個(gè)對(duì)象或一個(gè)字符串,如果options是一個(gè)字符串,它將自動(dòng)得被url.parse()翻譯。

Options:

  • host: 一個(gè)將要向其發(fā)送請(qǐng)求的服務(wù)器域名或IP地址。默認(rèn)為localhost。
  • hostname: host的別名。為了支持url.parse()的話,hostnamehost更好些。
  • family: 解析hosthostname時(shí)的IP地址協(xié)議族。合法值是46。當(dāng)沒(méi)有指定時(shí),將都被使用。
  • port: 遠(yuǎn)程服務(wù)器端口。默認(rèn)為80。
  • localAddress: 用于綁定網(wǎng)絡(luò)連接的本地端口。
  • socketPath: Unix域socket(使用host:portsocketPath)。
  • method: 指定HTTP請(qǐng)求方法的字符串。默認(rèn)為GET。
  • path: 請(qǐng)求路徑。默認(rèn)為/。如果有查詢(xún)字符串,則需要包含。例如'/index.html?page=12'。請(qǐng)求路徑包含非法字符時(shí)拋出異常。目前,只否決空格,不過(guò)在未來(lái)可能改變。
  • headers: 一個(gè)包含請(qǐng)求頭的對(duì)象。
  • auth: 用于計(jì)算認(rèn)證頭的基本認(rèn)證,即'user:password'。
  • agent: 控制agent行為。當(dāng)使用一個(gè)代理時(shí),請(qǐng)求將默認(rèn)為Connection: keep-alive??赡苤涤校?/p>

  • undefined (默認(rèn)): 在這個(gè)主機(jī)和端口上使用全局`agent。
  • Agent object: 在agent中顯示使用passed。
  • false: 跳出agent的連接池。默認(rèn)請(qǐng)求為Connection: close。

可選的回調(diào)函數(shù)將會(huì)被添加為response事件的“一次性”監(jiān)聽(tīng)器(one time listener)。

http.request()返回一個(gè)http.ClientRequest類(lèi)的實(shí)例。這個(gè)ClientRequest實(shí)例是一個(gè)可寫(xiě)流。如果你需要使用POST請(qǐng)求上傳一個(gè)文件,那么就將之寫(xiě)入這個(gè)ClientRequest對(duì)象。

例子:

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();

注意,在例子中調(diào)用了req.end()。使用http.request()時(shí)必須調(diào)用req.end()來(lái)表明你已經(jīng)完成了請(qǐng)求(即使沒(méi)有數(shù)據(jù)要被寫(xiě)入請(qǐng)求體)。

如果有一個(gè)錯(cuò)誤在請(qǐng)求時(shí)發(fā)生(如DNS解析,TCP級(jí)別錯(cuò)誤或?qū)嶋H的HTTP解析錯(cuò)誤),一個(gè)error事件將會(huì)在返回對(duì)象上觸發(fā)。

下面有一些特殊的需要主要的請(qǐng)求頭:

  • 發(fā)送'Connection: keep-alive'會(huì)告知io.js保持連直到下一個(gè)請(qǐng)求發(fā)送。

  • 發(fā)送'Content-length'頭會(huì)禁用默認(rèn)的數(shù)據(jù)塊編碼。

  • 發(fā)送'Expect'頭將會(huì)立刻發(fā)送一個(gè)請(qǐng)求頭。通常,當(dāng)發(fā)送'Expect: 100-continue'時(shí),你需要同時(shí)設(shè)置一個(gè)超時(shí)和監(jiān)聽(tīng)后續(xù)的時(shí)間。參閱RFC2616的8.2.3章節(jié)來(lái)獲取更多信息。

  • 發(fā)送一個(gè)授權(quán)頭將會(huì)覆蓋使用auth選項(xiàng)來(lái)進(jìn)行基本授權(quán)。

http.get(options[, callback])

由于大多數(shù)請(qǐng)求是沒(méi)有請(qǐng)求體的GET請(qǐng)求。io.js提供了這個(gè)簡(jiǎn)便的方法。這個(gè)方法和http.request()方法的唯一區(qū)別是它設(shè)置請(qǐng)求方法為GET且自動(dòng)調(diào)用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是用來(lái)把HTTP客戶(hù)端請(qǐng)求中的socket做成池。

HTTP Agent 也把客戶(hù)端的請(qǐng)求默認(rèn)為使用Connection:keep-alive。如果沒(méi)有HTTP請(qǐng)求正在等待成為空閑的套接字的話,那么套接字將關(guān)閉。這意味著io.js的資源池在負(fù)載的情況下對(duì)keep-alive有利,但是仍然不需要開(kāi)發(fā)人員使用KeepAlive來(lái)手動(dòng)關(guān)閉HTTP客戶(hù)端。

如果你選擇使用HTTP KeepAlive,那么你可以創(chuàng)建一個(gè)標(biāo)志設(shè)為true的Agent對(duì)象(見(jiàn)下面的構(gòu)造函數(shù)選項(xiàng))。然后,Agent將會(huì)在資源池中保持未被使用的套接字,用于未來(lái)使用。它們將會(huì)被顯式標(biāo)記,以便于不保持io.js進(jìn)程的運(yùn)行。但是當(dāng)KeepAlive agent沒(méi)有被使用時(shí),顯式地destroy() KeepAlive agent仍然是個(gè)好主意,這樣socket會(huì)被關(guān)閉。

當(dāng)socket觸發(fā)了close事件或者特殊的agentRemove事件的時(shí)候,套接字們從agent的資源池中移除。這意味著如果你打算保持一個(gè)HTTP請(qǐng)求長(zhǎng)時(shí)間開(kāi)啟,并且不希望它保持在資源池中,那么你可以按照下列幾行的代碼做事:

http.get(options, function(res) {
  // Do stuff
}).on("socket", function (socket) {
  socket.emit("agentRemove");
});

另外,你可以使用agent:false來(lái)停用池:

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設(shè)置可配置的選項(xiàng)。可以有以下屬性:

  • keepAlive Boolean 在未來(lái)保持池中的socket被其他請(qǐng)求所使用,默認(rèn)為false
  • keepAliveMsecs Integer 當(dāng)使用HTTP KeepAlive時(shí),通過(guò)被保持連接的socket發(fā)送TCP KeepAlive 報(bào)文的間隔。默認(rèn)為1000。只在KeepAlive被設(shè)置為true時(shí)有效
  • maxSockets Number 每個(gè)主機(jī)允許擁有的socket的最大數(shù)量。默認(rèn)為Infinity
  • maxFreeSockets Number 在空閑狀態(tài)下允許打開(kāi)的最大socket數(shù)。僅在keepAlivetrue時(shí)有效。默認(rèn)為256

http.request使用的默認(rèn)的http.globalAgent包含它們屬性的各自的默認(rèn)值。

為了配置它們中的任何一個(gè),你必須創(chuàng)建你自己的Agent對(duì)象。

var http = require('http');
var keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
http.request(options, onResponseCallback);

agent.maxSockets

默認(rèn)為Infinity。決定了每個(gè)源上可以擁有的并發(fā)的socket的數(shù)量。源為'host:port''host:port:localAddress'結(jié)合體。

agent.maxFreeSockets

默認(rèn)為256。對(duì)于支持HTTP KeepAlive的Agent,這設(shè)置了在空閑狀態(tài)下保持打開(kāi)的最大socket數(shù)量。

agent.sockets

這個(gè)對(duì)象包含了正在被Agent使用desocket數(shù)組。請(qǐng)不要修改它。

agent.freeSockets

這個(gè)對(duì)象包含了當(dāng)HTTP KeepAlive被使用時(shí)正在等待的socket數(shù)組。請(qǐng)不要修改它。

agent.requests

這個(gè)對(duì)象包含了還沒(méi)有被分配給socket的請(qǐng)求隊(duì)列。請(qǐng)不要修改它。

agent.destroy()

銷(xiāo)毀正在被agent使用的所有socket。

通常沒(méi)有必要這么做。但是,如果你正在使用一個(gè)啟用了KeepAlive的agent,那么最好明確地關(guān)閉agent當(dāng)你知道它不會(huì)再被使用時(shí)。否則,在服務(wù)器關(guān)閉它們前socket可能被閑置。

agent.getName(options)

通過(guò)一個(gè)請(qǐng)求選項(xiàng)集合來(lái)獲取一個(gè)獨(dú)一無(wú)二的名字,來(lái)決定一個(gè)連接是否可被再使用。在http代理中,這返回host:port:localAddress。在https代理中,name包括了CA,cert,ciphers和HTTPS/TLS-specific配置來(lái)決定一個(gè)socket是否能被再使用。

http.globalAgent

所有的http客戶(hù)端請(qǐng)求使用的默認(rèn)全局Agent實(shí)例。

Class: http.ClientRequest

這個(gè)對(duì)象時(shí)被內(nèi)部創(chuàng)建的,并且通過(guò)http.request()被返回。它代表了一個(gè)正在處理的請(qǐng)求,其頭部已經(jīng)進(jìn)入了隊(duì)列。這個(gè)頭部仍然可以通過(guò)setHeader(name, value)getHeader(name)removeHeader(name)修改。實(shí)際的頭部會(huì)隨著第一個(gè)數(shù)據(jù)塊發(fā)送,或在關(guān)閉連接時(shí)發(fā)送。

要獲得響應(yīng)對(duì)象,請(qǐng)為response事件添加一個(gè)監(jiān)聽(tīng)器。request對(duì)象的response事件將會(huì)在收到響應(yīng)頭時(shí)觸發(fā)。這個(gè)response事件的第一個(gè)參數(shù)是一個(gè)http.IncomingMessage的實(shí)例。

response事件期間,可以給響應(yīng)對(duì)象添加監(jiān)聽(tīng)器;尤其是監(jiān)聽(tīng)data事件。

如果沒(méi)有添加response事件監(jiān)聽(tīng)器,那么響應(yīng)會(huì)被完全忽略。但是,如果你添加了response事件,那么你必須通過(guò)調(diào)用response.read(),添加data事件監(jiān)聽(tīng)器或調(diào)用.resume()方法等等,來(lái)從響應(yīng)對(duì)象中消耗數(shù)據(jù)。在數(shù)據(jù)被消費(fèi)之前,end事件不會(huì)觸發(fā)。如果數(shù)據(jù)沒(méi)有被讀取,它會(huì)消耗內(nèi)存,最后導(dǎo)致'process out of memory'錯(cuò)誤。

注意:io.js不會(huì)檢查Content-Length和被傳輸?shù)捻憫?yīng)體長(zhǎng)度是否相同。

這個(gè)請(qǐng)求實(shí)現(xiàn)了Writable流接口。這是一個(gè)包含了以下事件的EventEmitter

Event: 'response'

  • function (response) { }

當(dāng)這個(gè)請(qǐng)求收到一個(gè)響應(yīng)時(shí)觸發(fā)。這個(gè)事件只會(huì)被觸發(fā)一次。response參數(shù)是一個(gè)http.IncomingMessage實(shí)例。

  • Options:

  • host: 一個(gè)向其發(fā)送請(qǐng)求的服務(wù)器的域名或IP地址
  • port: 遠(yuǎn)程服務(wù)器的端口
  • socketPath: Unix域socket(使用host:portsocketPath中的一個(gè))

Event: 'socket'

  • function (socket) { }

當(dāng)一個(gè)socket被分配給一個(gè)請(qǐng)求時(shí)觸發(fā)。

Event: 'connect'

  • function (response, socket, head) { }

每次服務(wù)器使用CONNECT方法響應(yīng)一個(gè)請(qǐng)求時(shí)觸發(fā)。如果這個(gè)事件沒(méi)有被監(jiān)聽(tīng),那么接受CONNECT方法的客戶(hù)端將會(huì)關(guān)閉它們的連接。

以下是一對(duì)客戶(hù)端/服務(wù)器代碼,展示如何監(jiān)聽(tīng)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.每次服務(wù)器返回upgrade響應(yīng)給請(qǐng)求時(shí)觸發(fā)。如果這個(gè)事件沒(méi)有被監(jiān)聽(tīng),客戶(hù)端接收一個(gè)upgrade頭時(shí)會(huì)關(guān)閉它們的連接。

以下是一對(duì)客戶(hù)端/服務(wù)器代碼,展示如何監(jiān)聽(tīng)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 () { }

當(dāng)服務(wù)器發(fā)出一個(gè)'100 Continue'HTTP響應(yīng)時(shí),通常這是因?yàn)檎?qǐng)求包含'Expect: 100-continue'。這是一個(gè)客戶(hù)端須要發(fā)送請(qǐng)求體的指示。

Event: 'abort'

  • function () { }

當(dāng)請(qǐng)求被客戶(hù)端中止時(shí)觸發(fā)。這個(gè)事件只會(huì)在第一次調(diào)用abort()時(shí)觸發(fā)。

request.flushHeaders()

沖刷請(qǐng)求頭。

由于效率原因,io.js通常在直到你調(diào)用request.end()或?qū)懭氲谝粋€(gè)數(shù)據(jù)塊前都會(huì)緩沖請(qǐng)求頭,然后努力將請(qǐng)求頭和數(shù)據(jù)打包為一個(gè)TCP報(bào)文。

這通常是你想要的(它節(jié)約了一個(gè)TCP往返)。但當(dāng)?shù)谝环輸?shù)據(jù)會(huì)等待很久才被發(fā)送時(shí)不是。request.flushHeaders()使你能繞過(guò)這個(gè)優(yōu)化并且啟動(dòng)請(qǐng)求。

request.write(chunk[, encoding][, callback])

發(fā)送一個(gè)響應(yīng)塊。當(dāng)用戶(hù)想要將請(qǐng)求體流式得發(fā)送給服務(wù)器時(shí),可以通過(guò)調(diào)用這個(gè)方法多次來(lái)辦到--在這種情況下,建議在創(chuàng)建請(qǐng)求時(shí)使用['Transfer-Encoding', 'chunked']頭。

chunk參數(shù)必須是一個(gè)Buffer或一個(gè)字符串。

encoding參數(shù)是可選的,并且僅當(dāng)chunk是字符串時(shí)有效。默認(rèn)為'utf8'。

callback參數(shù)是可選的,并且當(dāng)數(shù)據(jù)塊被沖刷時(shí)被調(diào)用。

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

結(jié)束發(fā)送請(qǐng)求。如果有任何部分的請(qǐng)求體未被發(fā)送,這個(gè)函數(shù)將會(huì)將它們沖刷至流中。如果請(qǐng)求是成塊的,它會(huì)發(fā)送終結(jié)符'0\r\n\r\n'。

如果data被指定,那么這與調(diào)用request.write(data, encoding)后再調(diào)用request.end(callback)相同。

如果callback被指定,那么它將在請(qǐng)求流結(jié)束時(shí)被調(diào)用。

request.abort()

中止請(qǐng)求。

request.setTimeout(timeout[, callback])

一旦一個(gè)socket被分配給這個(gè)請(qǐng)求并且完成連接,socket.setTimeout()會(huì)被調(diào)用。

返回request對(duì)象。

request.setNoDelay([noDelay])

一旦一個(gè)socket被分配給這個(gè)請(qǐng)求并且完成連接,socket.setNoDelay()會(huì)被調(diào)用。

request.setSocketKeepAlive([enable][, initialDelay])

一旦一個(gè)socket被分配給這個(gè)請(qǐng)求并且完成連接,socket.setKeepAlive()會(huì)被調(diào)用。

http.IncomingMessage

一個(gè)IncomingMessage對(duì)象被http.Serverhttp.ClientRequest創(chuàng)建,并且分別被傳遞給requestresponse事件的第一個(gè)參數(shù)。它被用來(lái)取得響應(yīng)狀態(tài),響應(yīng)頭和響應(yīng)體。

它實(shí)現(xiàn)了Readable流接口,并且有以下額外的事件,方法和屬性。

Event: 'close'

  • function () { }

表明底層連接被關(guān)閉。與end相同,這個(gè)時(shí)間每次響應(yīng)只會(huì)觸發(fā)一次。

message.httpVersion

當(dāng)向服務(wù)器發(fā)送請(qǐng)求時(shí),客戶(hù)端發(fā)送的HTTP版本。向客戶(hù)端發(fā)送響應(yīng)時(shí),服務(wù)器響應(yīng)的HTTP版本。通常是'1.1''1.0'

另外,response.httpVersionMajor是第一個(gè)整數(shù),response.httpVersionMinor是第二個(gè)整數(shù)。

message.headers

請(qǐng)求/響應(yīng)頭對(duì)象。

只讀的頭名稱(chēng)和值映射。頭名稱(chēng)是小寫(xiě)的,例子:

// Prints something like:
//
// { 'user-agent': 'curl/7.22.0',
//   host: '127.0.0.1:8000',
//   accept: '*/*' }
console.log(request.headers);

message.rawHeaders

接受到的原始請(qǐng)求/響應(yīng)頭列表。

注意鍵和值在同一個(gè)列表中,它并非一個(gè)元組列表。于是,偶數(shù)偏移量為鍵,奇數(shù)偏移量為對(duì)應(yīng)的值。

頭名稱(chēng)不是必須小寫(xiě)的,并且重復(fù)也沒(méi)有被合并。

// 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

請(qǐng)求/響應(yīng)尾部對(duì)象。只在end事件中存在。

message.rawTrailers

接受到的原始請(qǐng)求/響應(yīng)頭尾部鍵值對(duì)。只在end事件中存在。

message.setTimeout(msecs, callback)

  • msecs Number
  • callback Function

調(diào)用message.connection.setTimeout(msecs, callback)。

返回message

message.method

僅對(duì)從http.Server獲得的請(qǐng)求有效。

請(qǐng)求方法是字符串。只讀。例如:'GET','DELETE'。

message.url

僅對(duì)從http.Server獲得的請(qǐng)求有效。

請(qǐng)求的URL字符串。這僅僅只包含實(shí)際HTTP請(qǐng)求中的URL。如果請(qǐng)求是:

GET /status?name=ryan HTTP/1.1\r\n
Accept: text/plain\r\n
\r\n

那么request.url將是:

'/status?name=ryan'

如果你想分塊地解釋URL。你可以調(diào)用require('url').parse(request.url)。例子:

iojs> require('url').parse('/status?name=ryan')
{ href: '/status?name=ryan',
  search: '?name=ryan',
  query: 'name=ryan',
  pathname: '/status' }

如果你想從查詢(xún)字符串中提取參數(shù),你可以使用require('querystring').parse函數(shù),或者給require('url').parse方法的第二個(gè)參數(shù)傳遞true,例子:

iojs> require('url').parse('/status?name=ryan', true)
{ href: '/status?name=ryan',
  search: '?name=ryan',
  query: { name: 'ryan' },
  pathname: '/status' }

message.statusCode

只對(duì)從http.ClientRequest到來(lái)的響應(yīng)有效。

3位整數(shù)HTTP狀態(tài)碼。如404。

message.statusMessage

只對(duì)從http.ClientRequest到來(lái)的響應(yīng)有效。

HTTP響應(yīng)狀態(tài)信息。如OKInternal Server Error

message.socket

與此連接關(guān)聯(lián)的net.Socket對(duì)象。

通過(guò)HTTPS的支持,使用request.socket.getPeerCertificate()來(lái)獲取客戶(hù)端的身份細(xì)節(jié)。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)