第五天筆記 nodejs-http

使用 HTTP 服務(wù)器或客戶端功能必須調(diào)用require('http')。

Node 里的 HTTP 接口支持協(xié)議里原本比較難用的特性。特別是很大的或塊編碼的消息饮焦。這些接口不會完全緩存整個請求或響應(yīng),這樣用戶可以在請求或響應(yīng)中使用數(shù)據(jù)流。

HTTP消息頭對象和下面的例子類似:

{ 'content-length': '123',

'content-type': 'text/plain',

'connection': 'keep-alive',

'host': 'mysite.com',

'accept': '*/*' }

Keys 都是小寫囱皿,值不能修改勇婴。

為了能支持盡可能多的 HTTP 應(yīng)用程序,Node 提供的 HTTP API 接口都是底層的嘱腥。僅能處理流和消息耕渴。它把消息解析成報文頭和報文體,但是不解析實際的報文頭和報文體內(nèi)容齿兔。

定義報文頭的時候橱脸,多個值間可用,分隔。除了set-cookie和cookie頭分苇,因為它們表示值的數(shù)組添诉。諸如content-length的只有一個值的報文頭,直接解析医寿,并且只有單值可以表示成已經(jīng)解析好的對象栏赴。

接收到的原始頭信息以數(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.METHODS

{Array}

解析器支持的 HTTP 方法列表须眷。

http.STATUS_CODES

{Object}

全部標(biāo)準(zhǔn) HTTP 響應(yīng)狀態(tài)碼的和描述的集合。例如沟突,http.STATUS_CODES[404] === 'Not Found'花颗。

http.createServer([requestListener])

返回http.Server的新實例。

requestListener函數(shù)自動加到'request'事件里惠拭。

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

這個函數(shù)已經(jīng)被拋棄扩劝,用http.request()替換。創(chuàng)建一個新的 HTTP 客戶端职辅,連接到服務(wù)器的port和host棒呛。

類: http.Server

這是事件分發(fā)器EventEmitter,有以下事件:

事件: 'request'

function (request, response) { }

每當(dāng)有請求的時候觸發(fā)域携。注意:每個連接可以有多個請求(在 keep-alive 連接中)条霜。request是http.IncomingMessage實例,response是http.ServerResponse的實例涵亏。

事件: 'connection'

function (socket) { }

當(dāng)建立新的 TCP 流的時候宰睡。socket是一個net.Socket對象。通常用戶不會訪問這個事件气筋。協(xié)議解析器綁定套接字時采用的方式使套接字不會出發(fā) readable 事件拆内。也能通過request.connection訪問socket。

事件: 'close'

function () { }

服務(wù)器關(guān)閉的時候觸發(fā)宠默。

事件: 'checkContinue'

function (request, response) { }

當(dāng) http 收到 100-continue 的 http 請求時會觸發(fā)麸恍。如果沒有監(jiān)聽這個事件,服務(wù)器將會自動發(fā)送 100 Continue 的響應(yīng)。

如果客戶端需要繼續(xù)發(fā)送請求主題抹沪,或者生成合適的 HTTP 響應(yīng)(如刻肄,400 請求無效),可以通過調(diào)用response.writeContinue()來處理融欧。

注意:觸發(fā)并處理這個事件的時候敏弃,不會再觸發(fā)request事件。

事件: 'connect'

function (request, socket, head) { }

當(dāng)客戶端請求 http 連接時觸發(fā)噪馏。如果沒有監(jiān)聽這個事件麦到,客戶端請求連接的時候會被關(guān)閉。

request是 http 請求的參數(shù)欠肾,與 request 事件參數(shù)相同瓶颠。

socket是服務(wù)器和客戶端間的 socket。

head是 buffer 的實例刺桃。網(wǎng)絡(luò)隧道的第一個包粹淋,可能為空。

這個事件觸發(fā)后瑟慈,請求的 socket 不會有data事件監(jiān)聽器桃移,也就是說你需要綁定一個監(jiān)聽器到data上,來處理在發(fā)送到服務(wù)器上的 socket 數(shù)據(jù)封豪。

事件: 'upgrade'

function (request, socket, head) { }

當(dāng)客戶端請求 http upgrage 時候會觸發(fā)谴轮。如果沒有監(jiān)聽這個事件炒瘟,客戶端請求一個連接的時候會被關(guān)閉吹埠。

request是 http 請求的參數(shù),與 request 事件參數(shù)相同疮装。

socket是服務(wù)器和客戶端間的 socket缘琅。

head是 buffer 的實例。網(wǎng)絡(luò)隧道的第一個包廓推,可能為空刷袍。

這個事件觸發(fā)后,請求的 socket 不會有data事件監(jiān)聽器樊展,也就是說你需要綁定一個監(jiān)聽器到data上呻纹,來處理在發(fā)送到服務(wù)器上的 socket 數(shù)據(jù)。

事件: 'clientError'

function (exception, socket) { }

如果一個客戶端連接觸發(fā)了一個 'error' 事件, 它就會轉(zhuǎn)發(fā)到這里.

socket是導(dǎo)致錯誤的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_backlogandsomaxconn)吩跋。默認(rèn)參數(shù)值為 511 (不是 512)

這是異步函數(shù)寞射。最后一個參數(shù)callback會作為事件監(jiān)聽器添加到listening事件。參見net.Server.listen(port)锌钮。

server.listen(path[, callback])

啟動一個 UNIX socket 服務(wù)器所給路徑path

這是異步函數(shù)桥温。最后一個參數(shù)callback會作為事件監(jiān)聽器添加到listening事件。參見net.Server.listen(port)轧粟。

server.listen(handle[, callback])

handle{Object}

callback{Function}

handle對象可以是 server 或 socket(任意以下劃線_handle開頭的成員)策治,或者{fd: }對象。

這會導(dǎo)致 server 用參數(shù)handle接收連接兰吟,前提條件是文件描述符或句柄已經(jīng)連接到端口或域 socket通惫。

Windows 不能監(jiān)聽文件句柄。

這是異步函數(shù)混蔼。最后一個參數(shù)callback會作為事件監(jiān)聽器添加到listening事件履腋。參見net.Server.listen(port)

server.close([callback])

禁止 server 接收連接惭嚣。參見net.Server.close().

server.maxHeadersCount

最大請求頭的數(shù)量限制遵湖,默認(rèn) 1000。如果設(shè)置為 0晚吞,則不做任何限制延旧。

server.setTimeout(msecs, callback)

msecs{Number}

callback{Function}

為 socket 設(shè)置超時時間,單位為毫秒槽地,如果發(fā)生超時迁沫,在 server 對象上觸發(fā)'timeout'事件,參數(shù)為 socket 捌蚊。

如果在 Server 對象上有一個'timeout'事件監(jiān)聽器集畅,超時的時候,將會調(diào)用它缅糟,參數(shù)為 socket 挺智。

默認(rèn)情況下,Server 的超時為 2 分鐘窗宦,如果超時將會銷毀 socket赦颇。如果你給 Server 的超時事件設(shè)置了回調(diào)函數(shù),那你就得負(fù)責(zé)處理 socket 超時赴涵。

server.timeout

{Number} Default = 120000 (2 minutes)

超時的時長媒怯,單位為毫秒。

注意句占,socket 的超時邏輯在連接時設(shè)定沪摄,所以有新的連接時才能改變這個值。

設(shè)為 0 時,建立連接的自動超時將失效杨拐。

類: http.ServerResponse

這是一個由 HTTP 服務(wù)器(而不是用戶)內(nèi)部創(chuàng)建的對象祈餐。作為第二個參數(shù)傳遞給'request'事件。

該響應(yīng)實現(xiàn)了Writable Stream接口哄陶。這是一個包含下列事件的EventEmitter

事件: 'close'

function () { }

在調(diào)用response.end()帆阳,或準(zhǔn)備 flush 前,底層連接結(jié)束屋吨。

事件: 'finish'

function () { }

發(fā)送完響應(yīng)觸發(fā)蜒谤。響應(yīng)頭和響應(yīng)體最后一段數(shù)據(jù)被剝離給操作系統(tǒng)后,通過網(wǎng)絡(luò)來傳輸時被觸發(fā)至扰。這并不代表客戶端已經(jīng)收到數(shù)據(jù)鳍徽。

這個事件之后,響應(yīng)對象不會再觸發(fā)任何事件敢课。

response.writeContinue()

發(fā)送 HTTP/1.1 100 Continue 消息給客戶端阶祭,表示請求體可以發(fā)送≈备眩可以在服務(wù)器上查看'checkContinue'事件濒募。

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

發(fā)送一個響應(yīng)頭給請求。狀態(tài)碼是 3 位數(shù)字圾结,如404瑰剃。最后一個參數(shù)headers是響應(yīng)頭。建議第二個參數(shù)設(shè)置為可以看的懂的消息筝野。

例如:

var body = 'hello world';

response.writeHead(200, {

'Content-Length': body.length,

'Content-Type': 'text/plain' });

這個方法僅能在消息中調(diào)用一次晌姚,而且必須在response.end()前調(diào)用。

如果你在這之前調(diào)用response.write()response.end(),將會計算出不穩(wěn)定的頭遗座。

Content-Length 是字節(jié)數(shù)舀凛,而不是字符數(shù)俊扳。上面的例子'hello world'僅包含一個字節(jié)字符途蒋。如果 body 包含高級編碼的字符,Buffer.byteLength()就必須確定指定編碼的字符數(shù)馋记。Node 不會檢查Content-Length 和 body 的長度是否相同号坡。

response.setTimeout(msecs, callback)

msecs{Number}

callback{Function}

設(shè)置 socket 超時時間,單位為毫秒梯醒。如果提供了回調(diào)函數(shù)宽堆,將會在 response 對象的'timeout'事件上添加監(jiān)聽器。

如果沒有給請求茸习、響應(yīng)畜隶、服務(wù)器添加'timeout'監(jiān)視器,超時的時候?qū)N毀 socket。如果你給請求籽慢、響應(yīng)浸遗、服務(wù)器加了處理函數(shù),就需要負(fù)責(zé)處理 socket 超時箱亿。

response.statusCode

使用默認(rèn)的 headers 時(沒有顯式的調(diào)用response.writeHead())跛锌,這個屬性表示將要發(fā)送給客戶端狀態(tài)碼。

例如:

response.statusCode = 404;

響應(yīng)頭發(fā)送給客戶端的后届惋,這個屬性表示狀態(tài)碼已經(jīng)發(fā)送髓帽。

response.statusMessage

使用默認(rèn) headers 時(沒有顯式的調(diào)用response.writeHead()), 這個屬性表示將要發(fā)送給客戶端狀態(tài)信息。 如果這個沒有定義脑豹,將會使用狀態(tài)碼的標(biāo)準(zhǔn)消息郑藏。

例如:

response.statusMessage = 'Not found';

當(dāng)響應(yīng)頭發(fā)送給客戶端的時候,這個屬性表示狀態(tài)消息已經(jīng)發(fā)送瘩欺。

response.setHeader(name, value)

設(shè)置默認(rèn)頭某個字段內(nèi)容译秦。如果這個頭即將被發(fā)送,內(nèi)容會被替換击碗。如果你想設(shè)置更多的頭筑悴, 就使用一個相同名字的字符串?dāng)?shù)組。

例如:

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

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

response.headersSent

Boolean (只讀)稍途。如果headers發(fā)送完畢,則為 true,反之為 false阁吝。

response.sendDate

默認(rèn)值為 true。若為 true,當(dāng) headers 里沒有 Date 值時械拍,自動生成 Date 并發(fā)送突勇。

只有在測試環(huán)境才能禁用; 因為 HTTP 要求響應(yīng)包含 Date 頭.

response.getHeader(name)

讀取一個在隊列中但是還沒有被發(fā)送至客戶端的header。名字是大小寫敏感坷虑。僅能再頭被flushed前調(diào)用甲馋。

例如:

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

response.removeHeader(name)

從即將發(fā)送的隊列里移除頭。

例如:

response.removeHeader("Content-Encoding");

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

如果調(diào)用了這個方法迄损,且還沒有調(diào)用response.writeHead()定躏,將會切換到默認(rèn)的 header,并更新這個header芹敌。

這個方法將發(fā)送響應(yīng)體數(shù)據(jù)塊痊远。可能會多次調(diào)用這個方法氏捞,以提供 body 成功的部分內(nèi)容碧聪。

chunk可以是字符串或 buffer。如果chunk是字符串液茎,第二個參數(shù)表明如何將它編碼成字節(jié) 流逞姿。encoding的默認(rèn)值是'utf8'辞嗡。最后一個參數(shù)在刷新這個數(shù)據(jù)塊時調(diào)用。

注意:這個是原始的 HTTP body滞造,和高級的multi-part body 編碼無關(guān)欲间。

第一次調(diào)用response.write()的時候,將會發(fā)送緩存的頭信息和第一個 body 給客戶端断部。第二次猎贴,將會調(diào)用response.write()。Node 認(rèn)為你將會獨立發(fā)送流數(shù)據(jù)蝴光。這意味著她渴,響應(yīng)緩存在第一個數(shù)據(jù)塊中。

如果成功的刷新全部數(shù)據(jù)到內(nèi)核緩沖區(qū)蔑祟,返回true趁耗。如果部分或全部數(shù)據(jù)在用戶內(nèi)存中還處于排隊狀況,返回false疆虚。當(dāng)緩存再次釋放的時候苛败,將會觸發(fā)'drain'。

response.addTrailers(headers)

這個方法給響應(yīng)添加 HTTP 的尾部 header(消息末尾的 header)径簿。

只有數(shù)據(jù)塊編碼用于響應(yīng)體時罢屈,才會觸發(fā) Trailers;如果不是(例如篇亭,請求是HTTP/1.0)缠捌,它們將會被自動丟棄。

如果你想觸發(fā) trailers译蒂, HTTP 會要求發(fā)送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][, callback])

這個方法告訴服務(wù)器柔昼,所有的響應(yīng)頭和響應(yīng)體已經(jīng)發(fā)送哑芹;服務(wù)器可以認(rèn)為消息結(jié)束。response.end()方法必須在每個響應(yīng)中調(diào)用捕透。

如果指定了參數(shù)data聪姿,將會在響應(yīng)流結(jié)束的時候調(diào)用。

http.request(options[, callback])

Node 維護每個服務(wù)器的連接來生成 HTTP 請求激率。這個函數(shù)讓你可以發(fā)布請求咳燕。

參數(shù)options是對象或字符串勿决。如果options是字符串乒躺,會通過url.parse()自動解析。

options值:

host: 請求的服務(wù)器域名或 IP 地址低缩,默認(rèn):'localhost'

hostname: 用于支持url.parse()嘉冒。hostname優(yōu)于host

port: 遠(yuǎn)程服務(wù)器端口曹货。 默認(rèn): 80.

localAddress: 用于綁定網(wǎng)絡(luò)連接的本地接口

socketPath: Unix域 socket(使用host:port或socketPath

method: 指定 HTTP 請求方法。 默認(rèn):'GET'.

path: 請求路徑讳推。 默認(rèn):'/'顶籽。如果有查詢字符串,則需要包含银觅。例如'/index.html?page=12'礼饱。請求路徑包含非法字符時拋出異常。目前究驴,只有空格不行镊绪,不過在未來可能改變。

headers: 包含請求頭的對象

auth: 用于計算認(rèn)證頭的基本認(rèn)證洒忧,即user:password

agent: 控制Agent的行為蝴韭。當(dāng)使用了一個Agent的時候,請求將默認(rèn)為Connection: keep-alive熙侍¢可能的值為:

undefined(default): 在這個主機和端口上使用global Agent

Agentobject: 在Agent中顯式使用 passed .

false: 選擇性停用連接池,默認(rèn)請求為:Connection: close.

keepAlive: {Boolean} 持資源池周圍的socket,用于未來其它請求蛉抓。默認(rèn)值為false庆尘。

keepAliveMsecs: {Integer} 使用HTTP KeepAlive 的時候,通過正在保持活動的sockets發(fā)送TCP KeepAlive包的頻繁程度巷送。默認(rèn)值為1000减余。僅當(dāng)keepAlive為true時才相關(guān)。

可選參數(shù)callback將會作為一次性的監(jiān)視器惩系,添加給'response'事件位岔。

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

});

});

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()必須調(diào)用req.end()來表明請求已經(jīng)完成,即使沒有數(shù)據(jù)寫入到請求 body 里爬坑。

如果在請求的時候遇到錯誤(DNS 解析纠屋、TCP 級別的錯誤或?qū)嶋H HTTP 解析錯誤)售担,在返回的請求對象時會觸發(fā)一個 'error' 事件赁遗。

有一些特殊的頭需要注意:

發(fā)送Connection: keep-alive告訴服務(wù)器保持連接,直到下一個請求到來族铆。

發(fā)送Content-length頭將會禁用chunked編碼哥攘。

發(fā)送一個Expect頭,會立即發(fā)送請求頭末捣,一般來說创橄,發(fā)送Expect: 100-continue,你必須設(shè)置超時,并監(jiān)聽continue事件邦邦。更多細(xì)節(jié)參見 RFC2616 Section 8.2.3 燃辖。

發(fā)送一個授權(quán)頭网棍,將會使用auth參數(shù)重寫滥玷,來計算基本的授權(quán)。

http.get(options[, callback])

因為多數(shù)請求是沒有報文體的 GET 請求蛋欣, Node 提供了這個簡便的方法如贷。和http.request()唯一不同點在于杠袱,這個方法自動設(shè)置 GET,并自動調(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);

});

類: http.Agent

HTTP Agent 用于 socket 池缠劝,用于 HTTP 客戶端請求骗灶。

HTTP Agent 也把客戶端請求默認(rèn)為使用 Connection:keep-alive 耙旦。如果沒有 HTTP 請求正在等著成為空閑 socket 的話,那么 socket 將關(guān)閉免都。這意味著锉罐,Node 的資源池在負(fù)載的情況下對 keep-alive 有利绕娘,但是仍然不需要開發(fā)人員使用 KeepAlive 來手動關(guān)閉 HTTP 客戶端险领。

如果你選擇使用 HTTP KeepAlive, 可以創(chuàng)建一個 Agent 對象挨下,將 flag 設(shè)置為true. (參見下面的constructor options) 臭笆,這樣 Agent 會把沒用到的 socket 放到池里愁铺,以便將來使用闻鉴。他們會被顯式的標(biāo)志椒拗,讓 Node 不運行蚀苛。但是,當(dāng)不再使用它的時候腋舌,需要顯式的調(diào)用destroy()块饺,這樣 socket 將會被關(guān)閉授艰。

當(dāng) socket 事件觸發(fā)close事件或特殊的agentRemove事件時淮腾,socket 將會從 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 上的設(shè)置選項集合驶沼,有以下字段內(nèi)容:

keepAlive{Boolean} 持資源池周圍的 socket回怜,用于未來其它請求玉雾。默認(rèn)值為false复旬。

keepAliveMsecs{Integer} 使用 HTTP KeepAlive 的時候,通過正在保持活動的 sockets 發(fā)送 TCP KeepAlive 包的頻繁程度壁涎。默認(rèn)值為 1000怔球。僅當(dāng) keepAlive 為 true 時才相關(guān)竟坛。.】

maxSockets{Number} 在空閑狀態(tài)下,還依然開啟的 socket 的最大值。僅當(dāng)keepAlive設(shè)置為 true 的時候有效涎跨。默認(rèn)值為 256隅很。

被http.request使用的默認(rèn)的http.globalAgent,會設(shè)置全部的值為默認(rèn)外构。

必須在創(chuàng)建你自己的Agent對象后,才能配置這些值歧匈。

var http = require('http');

var keepAliveAgent = new http.Agent({ keepAlive: true });

options.agent = keepAliveAgent;

http.request(options, onResponseCallback);

agent.maxSockets

默認(rèn)值為 Infinity砰嘁。決定了每臺主機上的 agent 可以擁有的并發(fā) socket 的打開數(shù)量矮湘,主機可以是host:port或host:port:localAddress缅阳。

agent.maxFreeSockets

默認(rèn)值 256. 對于支持 HTTP KeepAlive 的 Agent 而言十办,這個方法設(shè)置了空閑狀態(tài)下仍然打開的套接字?jǐn)?shù)的最大值向族。

agent.sockets

這個對象包含了當(dāng)前 Agent 使用中的 socket 數(shù)組。不要修改它再扭。

agent.freeSockets

使用 HTTP KeepAlive 的時候泛范,這個對象包含等待當(dāng)前 Agent 使用的 socket 數(shù)組。不要修改它。

agent.requests

這個對象包含了還沒分配給 socket 的請求數(shù)組。不要修改它从媚。

agent.destroy()

銷毀任意一個被 agent 使用 的socket拜效。

通常情況下不要這么做紧憾。如果你正在使用一個允許 KeepAlive 的 agent赴穗,當(dāng)你知道不在使用它的時候膀息,最好關(guān)閉 agent潜支。否則冗酿,socket 會一直保存打開狀態(tài)已烤,直到服務(wù)器關(guān)閉胯究。

agent.getName(options)

獲取一組請求選項的唯一名裕循,來確定某個連接是否可重用。在 http agent 里硅则,它會返回host:port:localAddress怎虫。在 http agent 里大审, name 包括 CA徒扶,cert, ciphers, 和其他 HTTPS/TLS 特殊選項來決定 socket 是否可以重用姜骡。

http.globalAgent

Agent 的全局實例圈澈,是 http 客戶端的默認(rèn)請求。

類: http.ClientRequest

該對象在內(nèi)部創(chuàng)建并從http.request()返回闯两。他是正在處理的請求,其頭部已經(jīng)在隊列中饥臂。使用setHeader(name, value),getHeader(name),removeHeader(name)API 可以改變header隅熙。當(dāng)關(guān)閉連接的時候囚戚,header將會和第一個數(shù)據(jù)塊一起發(fā)送驰坊。

為了獲取響應(yīng)拳芙,可以給請求對象的'response'添加監(jiān)聽器舟扎。當(dāng)接收到響應(yīng)頭的時候?qū)恼埱髮ο罄镉|發(fā)'response'睹限。'response'事件執(zhí)行時有一個參數(shù)羡疗,該參數(shù)為http.IncomingMessage的實例。

在'response'事件期間肌索,可以給響應(yīng)對象添加監(jiān)視器诚亚,監(jiān)聽'data'事件站宗。

如果沒有添加'response'處理函數(shù)梢灭,響應(yīng)將被完全忽略敏释。如果你添加了'response'事件處理函數(shù)钥顽,那你必須消費掉從響應(yīng)對象獲取的數(shù)據(jù)蜂大,可以在'readable'事件里調(diào)用response.read()奶浦,或者添加一個'data'處理函數(shù)澳叉,或者調(diào)用.resume()方法耳高。如果未讀取數(shù)據(jù)泌枪,它將會消耗內(nèi)存碌燕,最終產(chǎn)生process out of memory錯誤修壕。

Node 不會檢查 Content-Length 和 body 的長度是否相同慈鸠。

該請求實現(xiàn)了Writable Stream接口青团。這是一個包含下列事件的EventEmitter督笆。

事件: 'response'

function (response) { }

當(dāng)接收到請求的時候會觸發(fā)娃肿,僅會觸發(fā)一次料扰。response的參數(shù)是http.IncomingMessage的實例记罚。

Options:

host: 要請求的服務(wù)器域名或 IP 地址

port: 遠(yuǎn)程服務(wù)器的端口

socketPath: Unix 域 Socket (使用 host:port 或 socketPath 之一)

事件: 'socket'

function (socket) { }

Socket 附加到這個請求的時候觸發(fā)桐智。

事件: 'connect'

function (response, socket, head) { }

每次服務(wù)器使用 CONNECT 方法響應(yīng)一個請求時觸發(fā)说庭。如果這個這個事件未被監(jiān)聽刊驴,接收 CONNECT 方法的客戶端將關(guān)閉他們的連接捆憎。

下面的例子展示了一對匹配的客戶端/服務(wù)器如何監(jiān)聽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: Node-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();

});

});

});

事件: 'upgrade'

function (response, socket, head) { }

每當(dāng)服務(wù)器響應(yīng) upgrade 請求時觸發(fā)。如果沒有監(jiān)聽這個事件,客戶端會收到 upgrade 頭后關(guān)閉連接滔蝉。

下面的例子展示了一對匹配的客戶端/服務(wù)器如何監(jiān)聽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);

});

});

事件: 'continue'

function () { }

當(dāng)服務(wù)器發(fā)送 '100 Continue' HTTP 響應(yīng)的時候觸發(fā),通常因為請求包含 'Expect: 100-continue'谅年。該指令表示客戶端應(yīng)發(fā)送請求體融蹂。

request.flushHeaders()

刷新請求的頭弄企。

考慮效率因素超燃,Node.js 通常會緩存請求的頭直到你調(diào)用request.end(),或?qū)懭胝埱蟮牡谝粋€數(shù)據(jù)塊拘领。然后意乓,包裝請求的頭和數(shù)據(jù)到一個獨立的 TCP 包里。

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

發(fā)送一個請求體的數(shù)據(jù)塊约素。通過多次調(diào)用這個函數(shù)届良,用戶能流式的發(fā)送請求給服務(wù)器圣猎,這種情況下士葫,建議使用['Transfer-Encoding', 'chunked']頭。

chunk參數(shù)必須是Buffer或字符串送悔。

回調(diào)參數(shù)可選慢显,當(dāng)這個數(shù)據(jù)塊被刷新的時候會被調(diào)用。

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

發(fā)送請求完畢欠啤。如果 body 的數(shù)據(jù)沒被發(fā)送荚藻,將會將他們刷新到流里。如果請求是分塊的洁段,該方法會發(fā)送終結(jié)符0\r\n\r\n 应狱。

如果指定了data,等同于先調(diào)用request.write(data, encoding)眉撵,再調(diào)用request.end(callback)侦香。

如果有callback落塑,將會在請求流結(jié)束的時候調(diào)用。

request.abort()

終止一個請求. (v0.3.8 開始新加入)罐韩。

request.setTimeout(timeout[, callback])

如果 socket 被分配給這個請求憾赁,并完成連接,將會調(diào)用socket.setTimeout()散吵。

request.setNoDelay([noDelay])

如果 socket 被分配給這個請求龙考,并完成連接,將會調(diào)用socket.setNoDelay()矾睦。

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

如果 socket 被分配給這個請求晦款,并完成連接,將會調(diào)用socket.setKeepAlive()枚冗。

http.IncomingMessage

http.Serverhttp.ClientRequest創(chuàng)建了IncomingMessage對象缓溅,作為第一個參數(shù)傳遞給'response'。它可以用來訪問應(yīng)答的狀態(tài)赁温,頭文件和數(shù)據(jù)坛怪。

它實現(xiàn)了Readable Stream接口,以及以下額外的事件股囊,方法和屬性袜匿。

事件: 'close'

function () { }

表示底層連接已經(jīng)關(guān)閉。 和'end'類似稚疹,這個事件每個應(yīng)答只會發(fā)送一次居灯。

message.httpVersion

客戶端向服務(wù)器發(fā)送請求時,客戶端發(fā)送的 HTTP 版本内狗;或者服務(wù)器想客戶端返回應(yīng)答時怪嫌,服務(wù)器的 HTTP 版本。通常是'1.1'或'1.0'其屏。

另外喇勋,response.httpVersionMajor是第一個整數(shù),response.httpVersionMinor是第二個整數(shù)偎行。

message.headers

請求/響應(yīng)頭對象。

只讀的頭名稱和值的映射贰拿。頭的名字是小寫蛤袒,比如:

// Prints something like:

//

// { 'user-agent': 'curl/7.22.0',

//? host: '127.0.0.1:8000',

//? accept: '*/*' }

console.log(request.headers);

message.rawHeaders

接收到的請求/響應(yīng)頭字段列表。

注意膨更,鍵和值在同一個列表中妙真。它并非一個元組列表。所以荚守,偶數(shù)偏移量為鍵珍德,奇數(shù)偏移量為對應(yīng)的值练般。

頭名字不是小寫敏感,也沒用合并重復(fù)的頭锈候。 // 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

請求/響應(yīng) 的尾部對象薄料。只在 'end' 事件中存在。

message.rawTrailers

接收到的原始的請求/響應(yīng)尾部鍵和值泵琳。僅在 'end' 事件中存在摄职。

message.setTimeout(msecs, callback)

msecs{Number}

callback{Function}

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

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),例如:

node> require('url').parse('/status?name=ryan')

{ href: '/status?name=ryan',

search: '?name=ryan',

query: 'name=ryan',

pathname: '/status' }

如果想從查詢字符串中解析出參數(shù)巩梢,可以用require('querystring').parse函數(shù)创泄,或者將true作為第二個參數(shù)傳遞給require('url').parse。 例如:

node> require('url').parse('/status?name=ryan', true)

{ href: '/status?name=ryan',

search: '?name=ryan',

query: { name: 'ryan' },

pathname: '/status' }

message.statusCode

僅對從http.ClientRequest獲取的響應(yīng)有效且改。

3位數(shù)的 HTTP 響應(yīng)狀態(tài)碼404验烧。

message.statusMessage

僅對從http.ClientRequest獲取的響應(yīng)有效。

HTTP 的響應(yīng)消息又跛。比如碍拆,OK或Internal Server Error.

message.socket

和連接相關(guān)聯(lián)的net.Socket對象。

通過 HTTPS 支持慨蓝,使用request.connection.verifyPeer()和request.connection.getPeerCertificate()獲取客戶端的身份信息感混。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市礼烈,隨后出現(xiàn)的幾起案子弧满,更是在濱河造成了極大的恐慌,老刑警劉巖此熬,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庭呜,死亡現(xiàn)場離奇詭異,居然都是意外死亡犀忱,警方通過查閱死者的電腦和手機募谎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阴汇,“玉大人数冬,你說我怎么就攤上這事〔笫” “怎么了拐纱?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵铜异,是天一觀的道長。 經(jīng)常有香客問我秸架,道長揍庄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任咕宿,我火速辦了婚禮币绩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘府阀。我一直安慰自己缆镣,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布试浙。 她就那樣靜靜地躺著董瞻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪田巴。 梳的紋絲不亂的頭發(fā)上钠糊,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音壹哺,去河邊找鬼抄伍。 笑死,一個胖子當(dāng)著我的面吹牛管宵,可吹牛的內(nèi)容都是我干的截珍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼箩朴,長吁一口氣:“原來是場噩夢啊……” “哼岗喉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炸庞,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤钱床,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后埠居,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體查牌,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年滥壕,在試婚紗的時候發(fā)現(xiàn)自己被綠了僧免。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡捏浊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撞叨,到底是詐尸還是另有隱情金踪,我是刑警寧澤浊洞,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站胡岔,受9級特大地震影響法希,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靶瘸,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一苫亦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怨咪,春花似錦屋剑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至匠楚,卻和暖如春巍膘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背芋簿。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工峡懈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人与斤。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓肪康,卻偏偏與公主長得像,于是被迫代替她去往敵國和親幽告。 傳聞我的和親對象是個殘疾皇子梅鹦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容