摘要:為了處理請(qǐng)求流上的錯(cuò)誤,我們將錯(cuò)誤記錄到并發(fā)送狀態(tài)碼以指示,但是,在實(shí)際應(yīng)用程序中,我們需要檢查錯(cuò)誤以確定正確的狀態(tài)碼和消息是什么,與通常的錯(cuò)誤一樣,你應(yīng)該查閱錯(cuò)誤文檔。通過(guò)對(duì)象發(fā)送狀態(tài)碼和數(shù)據(jù)。
HTTP事務(wù)的剖析
本指南的目的是讓你充分了解Node.js HTTP處理的過(guò)程,我們假設(shè)你在一般意義上知道HTTP請(qǐng)求的工作方式,無(wú)論語(yǔ)言或編程環(huán)境如何,我們還假設(shè)你對(duì)Node.js EventEmitters和Streams有點(diǎn)熟悉,如果你對(duì)它們不太熟悉,那么值得快速閱讀每個(gè)API文檔。
創(chuàng)建服務(wù)器任何節(jié)點(diǎn)Web服務(wù)器應(yīng)用程序在某些時(shí)候都必須創(chuàng)建Web服務(wù)器對(duì)象,這是通過(guò)使用createServer完成的。
const http = require("http"); const server = http.createServer((request, response) => { // magic happens here! });
傳遞給createServer的函數(shù)對(duì)于針對(duì)該服務(wù)器發(fā)出的每個(gè)HTTP請(qǐng)求都會(huì)調(diào)用一次,因此它被稱為請(qǐng)求處理程序,實(shí)際上,createServer返回的Server對(duì)象是一個(gè)EventEmitter,我們這里只是創(chuàng)建server對(duì)象的簡(jiǎn)寫,然后稍后添加監(jiān)聽器。
const server = http.createServer(); server.on("request", (request, response) => { // the same kind of magic happens here! });
當(dāng)HTTP請(qǐng)求命中服務(wù)器時(shí),node使用一些方便的對(duì)象調(diào)用請(qǐng)求處理函數(shù)來(lái)處理事務(wù)、request和response,我們很快就會(huì)講到。
為了實(shí)際處理請(qǐng)求,需要在server對(duì)象上調(diào)用listen方法,在大多數(shù)情況下,你需要傳遞給listen的是你希望服務(wù)器監(jiān)聽的端口號(hào),還有一些其他選項(xiàng),請(qǐng)參閱API參考。
方法、URL和Headers處理請(qǐng)求時(shí),你可能要做的第一件事就是查看方法和URL,以便采取適當(dāng)?shù)拇胧琋ode通過(guò)將方便的屬性放在request對(duì)象上來(lái)使這相對(duì)輕松。
const { method, url } = request;
注意:request對(duì)象是IncomingMessage的一個(gè)實(shí)例。
這里的method將始終是普通的HTTP方法/動(dòng)作,url是沒(méi)有服務(wù)器、協(xié)議或端口的完整URL,對(duì)于典型的URL,這意味著包括第三個(gè)正斜杠后的所有內(nèi)容。
Headers也不遠(yuǎn),它們?cè)谧约旱?b>request對(duì)象中,被稱為headers。
const { headers } = request; const userAgent = headers["user-agent"];
這里需要注意的是,無(wú)論客戶端實(shí)際發(fā)送它們的方式如何,所有headers都僅以小寫字母表示,這簡(jiǎn)化了為任何目的解析headers的任務(wù)。
如果重復(fù)某些headers,則它們的值將被覆蓋或以逗號(hào)分隔的字符串連接在一起,具體取決于header,在某些情況下,這可能會(huì)有問(wèn)題,因此rawHeaders也可用。
請(qǐng)求體收到POST或PUT請(qǐng)求時(shí),請(qǐng)求體可能對(duì)你的應(yīng)用程序很重要,獲取body數(shù)據(jù)比訪問(wèn)請(qǐng)求headers更復(fù)雜一點(diǎn),傳遞給處理程序的request對(duì)象實(shí)現(xiàn)了ReadableStream接口,就像任何其他流一樣,可以在其他地方監(jiān)聽或傳輸此流,我們可以通過(guò)監(jiān)聽流的"data"和"end"事件來(lái)直接從流中獲取數(shù)據(jù)。
每個(gè)"data"事件中發(fā)出的塊是一個(gè)Buffer,如果你知道它將是字符串?dāng)?shù)據(jù),那么最好的方法是在數(shù)組中收集數(shù)據(jù),然后在"end",連接并對(duì)其進(jìn)行字符串化。
let body = []; request.on("data", (chunk) => { body.push(chunk); }).on("end", () => { body = Buffer.concat(body).toString(); // at this point, `body` has the entire request body stored in it as a string });
注意:這看起來(lái)有點(diǎn)單調(diào)乏味,而且在很多情況下確實(shí)如此,幸運(yùn)的是,在npm上有像concat-stream和body這樣的模塊可以幫助隱藏一些邏輯,在走這條路之前,要很好地了解正在發(fā)生的事情,這就是為什么你在這里!關(guān)于錯(cuò)誤的簡(jiǎn)單介紹
由于request對(duì)象是一個(gè)ReadableStream,它也是一個(gè)EventEmitter,發(fā)生錯(cuò)誤時(shí)的行為與此類似。
request流中的錯(cuò)誤通過(guò)在流上發(fā)出"error"事件來(lái)呈現(xiàn),如果你沒(méi)有該事件的偵聽器,則會(huì)拋出錯(cuò)誤,這可能會(huì)導(dǎo)致Node.js程序崩潰。因此,你應(yīng)該在請(qǐng)求流上添加"error"偵聽器,即使你只是記錄它并繼續(xù)前進(jìn)(雖然最好發(fā)送某種HTTP錯(cuò)誤響應(yīng),稍后會(huì)詳細(xì)介紹)。
request.on("error", (err) => { // This prints the error message and stack trace to `stderr`. console.error(err.stack); });
還有其他方法可以處理這些錯(cuò)誤,例如其他抽象和工具,但始終要注意錯(cuò)誤可能并且確實(shí)會(huì)發(fā)生,并且你將不得不處理它們。
到目前為止我們已經(jīng)得到了什么此時(shí),我們已經(jīng)介紹了如何創(chuàng)建服務(wù)器,并從請(qǐng)求中獲取方法、URL、headers和body,當(dāng)我們將它們放在一起時(shí),它可能看起來(lái)像這樣:
const http = require("http"); http.createServer((request, response) => { const { headers, method, url } = request; let body = []; request.on("error", (err) => { console.error(err); }).on("data", (chunk) => { body.push(chunk); }).on("end", () => { body = Buffer.concat(body).toString(); // At this point, we have the headers, method, url and body, and can now // do whatever we need to in order to respond to this request. }); }).listen(8080); // Activates this server, listening on port 8080.
如果我們運(yùn)行此示例,我們將能夠接收請(qǐng)求,但不會(huì)響應(yīng)它們,實(shí)際上,如果你在Web瀏覽器中請(qǐng)求此示例,則你的請(qǐng)求將超時(shí),因?yàn)闆](méi)有任何內(nèi)容被發(fā)送回客戶端。
到目前為止,我們還沒(méi)有涉及響應(yīng)對(duì)象,它是ServerResponse的一個(gè)實(shí)例,它是一個(gè)WritableStream,它包含許多用于將數(shù)據(jù)發(fā)送回客戶端的有用方法,接下來(lái)我們將介紹。
HTTP狀態(tài)碼如果不設(shè)置它,響應(yīng)中的HTTP狀態(tài)碼始終為200,當(dāng)然,并非每個(gè)HTTP響應(yīng)都保證這一點(diǎn),并且在某些時(shí)候你肯定希望發(fā)送不同的狀態(tài)碼,為此,你可以設(shè)置statusCode屬性。
response.statusCode = 404; // Tell the client that the resource wasn"t found.
還有其他一些快捷方式,我們很快就會(huì)看到。
設(shè)置響應(yīng)HeadersHeaders是通過(guò)一個(gè)名為setHeader的方便方法設(shè)置的。
response.setHeader("Content-Type", "application/json"); response.setHeader("X-Powered-By", "bacon");
在響應(yīng)上設(shè)置headers時(shí),大小寫對(duì)其名稱不敏感,如果重復(fù)設(shè)置標(biāo)題,則設(shè)置的最后一個(gè)值是發(fā)送的值。
顯式發(fā)送Header數(shù)據(jù)我們已經(jīng)討論過(guò)的設(shè)置headers和狀態(tài)碼的方法假設(shè)你正在使用“隱式headers”,這意味著在開始發(fā)送body數(shù)據(jù)之前,你需要依賴node在正確的時(shí)間為你發(fā)送headers。
如果需要,可以將headers顯式寫入響應(yīng)流,為此,有一個(gè)名為writeHead的方法,它將狀態(tài)碼和headers寫入流。
response.writeHead(200, { "Content-Type": "application/json", "X-Powered-By": "bacon" });
一旦設(shè)置了headers(隱式或顯式),你就可以開始發(fā)送響應(yīng)數(shù)據(jù)了。
發(fā)送響應(yīng)體由于response對(duì)象是WritableStream,因此將響應(yīng)體寫入客戶端只需使用常用的流方法即可。
response.write(""); response.write(""); response.write("Hello, World!
"); response.write(""); response.write(""); response.end();
流上的end函數(shù)也可以接收一些可選數(shù)據(jù)作為流上的最后一位數(shù)據(jù)發(fā)送,因此我們可以如下簡(jiǎn)化上面的示例。
response.end("Hello, World!
");
注意:在開始向body寫入數(shù)據(jù)塊之前設(shè)置狀態(tài)和headers很重要,這是有道理的,因?yàn)閔eaders在HTTP響應(yīng)中位于body之前。關(guān)于錯(cuò)誤的另一件事
response流也可以發(fā)出"error"事件,在某些時(shí)候你也必須處理它,所有關(guān)于request流錯(cuò)誤的建議仍然適用于此處。
把它放在一起現(xiàn)在我們已經(jīng)了解了如何進(jìn)行HTTP響應(yīng),讓我們把它們放在一起,在前面的示例的基礎(chǔ)上,我們將創(chuàng)建一個(gè)服務(wù)器,用于發(fā)回用戶發(fā)送給我們的所有數(shù)據(jù),我們將使用JSON.stringify將該數(shù)據(jù)格式化為JSON。
const http = require("http"); http.createServer((request, response) => { const { headers, method, url } = request; let body = []; request.on("error", (err) => { console.error(err); }).on("data", (chunk) => { body.push(chunk); }).on("end", () => { body = Buffer.concat(body).toString(); // BEGINNING OF NEW STUFF response.on("error", (err) => { console.error(err); }); response.statusCode = 200; response.setHeader("Content-Type", "application/json"); // Note: the 2 lines above could be replaced with this next one: // response.writeHead(200, {"Content-Type": "application/json"}) const responseBody = { headers, method, url, body }; response.write(JSON.stringify(responseBody)); response.end(); // Note: the 2 lines above could be replaced with this next one: // response.end(JSON.stringify(responseBody)) // END OF NEW STUFF }); }).listen(8080);Echo服務(wù)器示例
讓我們簡(jiǎn)化前面的示例來(lái)進(jìn)行一個(gè)簡(jiǎn)單的echo服務(wù)器,它只是在響應(yīng)中發(fā)送請(qǐng)求中收到的任何數(shù)據(jù),我們需要做的就是從請(qǐng)求流中獲取數(shù)據(jù)并將該數(shù)據(jù)寫入響應(yīng)流,類似于我們之前所做的。
const http = require("http"); http.createServer((request, response) => { let body = []; request.on("data", (chunk) => { body.push(chunk); }).on("end", () => { body = Buffer.concat(body).toString(); response.end(body); }); }).listen(8080);
現(xiàn)在讓我們調(diào)整一下,我們只想在以下條件下發(fā)送echo:
請(qǐng)求方法是POST。
URL是/echo。
在任何其他情況下,我們只想響應(yīng)404。
const http = require("http"); http.createServer((request, response) => { if (request.method === "POST" && request.url === "/echo") { let body = []; request.on("data", (chunk) => { body.push(chunk); }).on("end", () => { body = Buffer.concat(body).toString(); response.end(body); }); } else { response.statusCode = 404; response.end(); } }).listen(8080);
注意:通過(guò)這種方式檢查URL,我們正在做一種“路由”的形式,其他形式的路由可以像switch語(yǔ)句一樣簡(jiǎn)單,也可以像express這樣的整個(gè)框架一樣復(fù)雜,如果你正在尋找可以進(jìn)行路由的東西,請(qǐng)嘗試使用router。
現(xiàn)在讓我們來(lái)簡(jiǎn)化一下吧,請(qǐng)記住,request對(duì)象是ReadableStream,response對(duì)象是WritableStream,這意味著我們可以使用pipe將數(shù)據(jù)從一個(gè)引導(dǎo)到另一個(gè),這正是我們想要的echo服務(wù)器!
const http = require("http"); http.createServer((request, response) => { if (request.method === "POST" && request.url === "/echo") { request.pipe(response); } else { response.statusCode = 404; response.end(); } }).listen(8080);
我們還沒(méi)有完成,正如本指南中多次提到的,錯(cuò)誤可以而且確實(shí)會(huì)發(fā)生,我們需要處理它們。
為了處理請(qǐng)求流上的錯(cuò)誤,我們將錯(cuò)誤記錄到stderr并發(fā)送400狀態(tài)碼以指示Bad Request,但是,在實(shí)際應(yīng)用程序中,我們需要檢查錯(cuò)誤以確定正確的狀態(tài)碼和消息是什么,與通常的錯(cuò)誤一樣,你應(yīng)該查閱錯(cuò)誤文檔。
在響應(yīng)中,我們只是將錯(cuò)誤記錄到stderr。
const http = require("http"); http.createServer((request, response) => { request.on("error", (err) => { console.error(err); response.statusCode = 400; response.end(); }); response.on("error", (err) => { console.error(err); }); if (request.method === "POST" && request.url === "/echo") { request.pipe(response); } else { response.statusCode = 404; response.end(); } }).listen(8080);
我們現(xiàn)在已經(jīng)介紹了處理HTTP請(qǐng)求的大部分基礎(chǔ)知識(shí),此時(shí),你應(yīng)該能夠:
使用請(qǐng)求處理程序函數(shù)實(shí)例化HTTP服務(wù)器,并讓它偵聽端口。
從request對(duì)象中獲取headers、URL、方法和body數(shù)據(jù)。
根據(jù)request對(duì)象中的URL和/或其他數(shù)據(jù)做出路由決策。
通過(guò)response對(duì)象發(fā)送headers、HTTP狀態(tài)碼和body數(shù)據(jù)。
從request對(duì)象和response對(duì)象管道數(shù)據(jù)。
處理request和response流中的流錯(cuò)誤。
從這些基礎(chǔ)知識(shí)中,可以構(gòu)建用于許多典型用例的Node.js HTTP服務(wù)器,這些API提供了許多其他功能,因此請(qǐng)務(wù)必閱讀有關(guān)EventEmitters、Streams和HTTP的API文檔。
上一篇:Node.js中的定時(shí)器 下一篇:使用不同的文件系統(tǒng)文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/100273.html
Node.js 指南 Node.js?是基于Chrome的V8 JavaScript引擎構(gòu)建的JavaScript運(yùn)行時(shí)。 常規(guī) 關(guān)于Node.js 入門指南 輕松分析Node.js應(yīng)用程序 Docker化Node.js Web應(yīng)用程序 遷移到安全的Buffer構(gòu)造函數(shù) Node.js核心概念 阻塞與非阻塞概述 Node.js事件循環(huán)、定時(shí)器和process.nextTick() 不要阻塞事...
摘要:中的定時(shí)器中的模塊包含在一段時(shí)間后執(zhí)行代碼的函數(shù),定時(shí)器不需要通過(guò)導(dǎo)入,因?yàn)樗蟹椒ǘ伎梢栽谌址秶鷥?nèi)模擬瀏覽器,要完全了解何時(shí)執(zhí)行定時(shí)器功能,最好先閱讀事件循環(huán)。 Node.js中的定時(shí)器 Node.js中的Timers模塊包含在一段時(shí)間后執(zhí)行代碼的函數(shù),定時(shí)器不需要通過(guò)require()導(dǎo)入,因?yàn)樗蟹椒ǘ伎梢栽谌址秶鷥?nèi)模擬瀏覽器JavaScript API,要完全了解何時(shí)執(zhí)行定...
摘要:快速檢查可能告訴我們,簡(jiǎn)單地從的域處理程序拋出將允許然后捕獲異常并執(zhí)行其自己的錯(cuò)誤處理程序,雖然情況并非如此,檢查后,你會(huì)看到堆棧只包含。 域模塊剖析 可用性問(wèn)題 隱式行為 開發(fā)人員可以創(chuàng)建新域,然后只需運(yùn)行domain.enter(),然后,它充當(dāng)將來(lái)拋出者無(wú)法觀察到的任何異常的萬(wàn)能捕捉器,允許模塊作者攔截不同模塊中不相關(guān)代碼的異常,防止代碼的發(fā)起者知道自己的異常。 以下是一個(gè)間接鏈...
摘要:避免使用最低公分母方法你可能想讓你的程序像最低公分母文件系統(tǒng)一樣,通過(guò)將所有文件名規(guī)范化為大寫,將所有文件名規(guī)范化為格式,并將所有文件時(shí)間戳標(biāo)準(zhǔn)化為秒分辨率,這是最小公分母的方法。 使用不同的文件系統(tǒng) Node公開了文件系統(tǒng)的許多功能,但并非所有文件系統(tǒng)都相似,以下是建議的最佳實(shí)踐,以便在使用不同的文件系統(tǒng)時(shí)保持代碼簡(jiǎn)單和安全。 文件系統(tǒng)行為 在使用文件系統(tǒng)之前,你需要知道它的行為方式...
摘要:建立該倉(cāng)庫(kù)的目的主要是整理收集學(xué)習(xí)資源,統(tǒng)一管理,方便隨時(shí)查找。目前整合的學(xué)習(xí)資源只是前端方向的,可能會(huì)存在漏缺比較好的資源,需要慢慢的完善它,歡迎在該上補(bǔ)充資源或者提供寶貴的建議。 說(shuō)明 平時(shí)的學(xué)習(xí)資源都比較的凌亂,看到好的資源都是直接收藏在瀏覽器的收藏夾中,這樣其實(shí)并不方便,整理在云筆記上,也不方便查看修改記錄,索性就整理在 github 上并開源出來(lái),希望幫助大家能夠更快的找到需...
閱讀 3680·2021-11-23 09:51
閱讀 1044·2021-11-19 11:30
閱讀 3369·2019-08-29 14:16
閱讀 3375·2019-08-29 12:12
閱讀 2373·2019-08-26 13:40
閱讀 3484·2019-08-26 12:21
閱讀 3081·2019-08-26 11:55
閱讀 2229·2019-08-26 11:35