摘要:為了處理請求流上的錯誤,我們將錯誤記錄到并發送狀態碼以指示,但是,在實際應用程序中,我們需要檢查錯誤以確定正確的狀態碼和消息是什么,與通常的錯誤一樣,你應該查閱錯誤文檔。通過對象發送狀態碼和數據。
HTTP事務的剖析
本指南的目的是讓你充分了解Node.js HTTP處理的過程,我們假設你在一般意義上知道HTTP請求的工作方式,無論語言或編程環境如何,我們還假設你對Node.js EventEmitters和Streams有點熟悉,如果你對它們不太熟悉,那么值得快速閱讀每個API文檔。
創建服務器任何節點Web服務器應用程序在某些時候都必須創建Web服務器對象,這是通過使用createServer完成的。
const http = require("http"); const server = http.createServer((request, response) => { // magic happens here! });
傳遞給createServer的函數對于針對該服務器發出的每個HTTP請求都會調用一次,因此它被稱為請求處理程序,實際上,createServer返回的Server對象是一個EventEmitter,我們這里只是創建server對象的簡寫,然后稍后添加監聽器。
const server = http.createServer(); server.on("request", (request, response) => { // the same kind of magic happens here! });
當HTTP請求命中服務器時,node使用一些方便的對象調用請求處理函數來處理事務、request和response,我們很快就會講到。
為了實際處理請求,需要在server對象上調用listen方法,在大多數情況下,你需要傳遞給listen的是你希望服務器監聽的端口號,還有一些其他選項,請參閱API參考。
方法、URL和Headers處理請求時,你可能要做的第一件事就是查看方法和URL,以便采取適當的措施,Node通過將方便的屬性放在request對象上來使這相對輕松。
const { method, url } = request;
注意:request對象是IncomingMessage的一個實例。
這里的method將始終是普通的HTTP方法/動作,url是沒有服務器、協議或端口的完整URL,對于典型的URL,這意味著包括第三個正斜杠后的所有內容。
Headers也不遠,它們在自己的request對象中,被稱為headers。
const { headers } = request; const userAgent = headers["user-agent"];
這里需要注意的是,無論客戶端實際發送它們的方式如何,所有headers都僅以小寫字母表示,這簡化了為任何目的解析headers的任務。
如果重復某些headers,則它們的值將被覆蓋或以逗號分隔的字符串連接在一起,具體取決于header,在某些情況下,這可能會有問題,因此rawHeaders也可用。
請求體收到POST或PUT請求時,請求體可能對你的應用程序很重要,獲取body數據比訪問請求headers更復雜一點,傳遞給處理程序的request對象實現了ReadableStream接口,就像任何其他流一樣,可以在其他地方監聽或傳輸此流,我們可以通過監聽流的"data"和"end"事件來直接從流中獲取數據。
每個"data"事件中發出的塊是一個Buffer,如果你知道它將是字符串數據,那么最好的方法是在數組中收集數據,然后在"end",連接并對其進行字符串化。
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 });
注意:這看起來有點單調乏味,而且在很多情況下確實如此,幸運的是,在npm上有像concat-stream和body這樣的模塊可以幫助隱藏一些邏輯,在走這條路之前,要很好地了解正在發生的事情,這就是為什么你在這里!關于錯誤的簡單介紹
由于request對象是一個ReadableStream,它也是一個EventEmitter,發生錯誤時的行為與此類似。
request流中的錯誤通過在流上發出"error"事件來呈現,如果你沒有該事件的偵聽器,則會拋出錯誤,這可能會導致Node.js程序崩潰。因此,你應該在請求流上添加"error"偵聽器,即使你只是記錄它并繼續前進(雖然最好發送某種HTTP錯誤響應,稍后會詳細介紹)。
request.on("error", (err) => { // This prints the error message and stack trace to `stderr`. console.error(err.stack); });
還有其他方法可以處理這些錯誤,例如其他抽象和工具,但始終要注意錯誤可能并且確實會發生,并且你將不得不處理它們。
到目前為止我們已經得到了什么此時,我們已經介紹了如何創建服務器,并從請求中獲取方法、URL、headers和body,當我們將它們放在一起時,它可能看起來像這樣:
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.
如果我們運行此示例,我們將能夠接收請求,但不會響應它們,實際上,如果你在Web瀏覽器中請求此示例,則你的請求將超時,因為沒有任何內容被發送回客戶端。
到目前為止,我們還沒有涉及響應對象,它是ServerResponse的一個實例,它是一個WritableStream,它包含許多用于將數據發送回客戶端的有用方法,接下來我們將介紹。
HTTP狀態碼如果不設置它,響應中的HTTP狀態碼始終為200,當然,并非每個HTTP響應都保證這一點,并且在某些時候你肯定希望發送不同的狀態碼,為此,你可以設置statusCode屬性。
response.statusCode = 404; // Tell the client that the resource wasn"t found.
還有其他一些快捷方式,我們很快就會看到。
設置響應HeadersHeaders是通過一個名為setHeader的方便方法設置的。
response.setHeader("Content-Type", "application/json"); response.setHeader("X-Powered-By", "bacon");
在響應上設置headers時,大小寫對其名稱不敏感,如果重復設置標題,則設置的最后一個值是發送的值。
顯式發送Header數據我們已經討論過的設置headers和狀態碼的方法假設你正在使用“隱式headers”,這意味著在開始發送body數據之前,你需要依賴node在正確的時間為你發送headers。
如果需要,可以將headers顯式寫入響應流,為此,有一個名為writeHead的方法,它將狀態碼和headers寫入流。
response.writeHead(200, { "Content-Type": "application/json", "X-Powered-By": "bacon" });
一旦設置了headers(隱式或顯式),你就可以開始發送響應數據了。
發送響應體由于response對象是WritableStream,因此將響應體寫入客戶端只需使用常用的流方法即可。
response.write(""); response.write(""); response.write("Hello, World!
"); response.write(""); response.write(""); response.end();
流上的end函數也可以接收一些可選數據作為流上的最后一位數據發送,因此我們可以如下簡化上面的示例。
response.end("Hello, World!
");
注意:在開始向body寫入數據塊之前設置狀態和headers很重要,這是有道理的,因為headers在HTTP響應中位于body之前。關于錯誤的另一件事
response流也可以發出"error"事件,在某些時候你也必須處理它,所有關于request流錯誤的建議仍然適用于此處。
把它放在一起現在我們已經了解了如何進行HTTP響應,讓我們把它們放在一起,在前面的示例的基礎上,我們將創建一個服務器,用于發回用戶發送給我們的所有數據,我們將使用JSON.stringify將該數據格式化為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服務器示例
讓我們簡化前面的示例來進行一個簡單的echo服務器,它只是在響應中發送請求中收到的任何數據,我們需要做的就是從請求流中獲取數據并將該數據寫入響應流,類似于我們之前所做的。
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);
現在讓我們調整一下,我們只想在以下條件下發送echo:
請求方法是POST。
URL是/echo。
在任何其他情況下,我們只想響應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);
注意:通過這種方式檢查URL,我們正在做一種“路由”的形式,其他形式的路由可以像switch語句一樣簡單,也可以像express這樣的整個框架一樣復雜,如果你正在尋找可以進行路由的東西,請嘗試使用router。
現在讓我們來簡化一下吧,請記住,request對象是ReadableStream,response對象是WritableStream,這意味著我們可以使用pipe將數據從一個引導到另一個,這正是我們想要的echo服務器!
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);
我們還沒有完成,正如本指南中多次提到的,錯誤可以而且確實會發生,我們需要處理它們。
為了處理請求流上的錯誤,我們將錯誤記錄到stderr并發送400狀態碼以指示Bad Request,但是,在實際應用程序中,我們需要檢查錯誤以確定正確的狀態碼和消息是什么,與通常的錯誤一樣,你應該查閱錯誤文檔。
在響應中,我們只是將錯誤記錄到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);
我們現在已經介紹了處理HTTP請求的大部分基礎知識,此時,你應該能夠:
使用請求處理程序函數實例化HTTP服務器,并讓它偵聽端口。
從request對象中獲取headers、URL、方法和body數據。
根據request對象中的URL和/或其他數據做出路由決策。
通過response對象發送headers、HTTP狀態碼和body數據。
從request對象和response對象管道數據。
處理request和response流中的流錯誤。
從這些基礎知識中,可以構建用于許多典型用例的Node.js HTTP服務器,這些API提供了許多其他功能,因此請務必閱讀有關EventEmitters、Streams和HTTP的API文檔。
上一篇:Node.js中的定時器 下一篇:使用不同的文件系統文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100273.html
Node.js 指南 Node.js?是基于Chrome的V8 JavaScript引擎構建的JavaScript運行時。 常規 關于Node.js 入門指南 輕松分析Node.js應用程序 Docker化Node.js Web應用程序 遷移到安全的Buffer構造函數 Node.js核心概念 阻塞與非阻塞概述 Node.js事件循環、定時器和process.nextTick() 不要阻塞事...
摘要:中的定時器中的模塊包含在一段時間后執行代碼的函數,定時器不需要通過導入,因為所有方法都可以在全局范圍內模擬瀏覽器,要完全了解何時執行定時器功能,最好先閱讀事件循環。 Node.js中的定時器 Node.js中的Timers模塊包含在一段時間后執行代碼的函數,定時器不需要通過require()導入,因為所有方法都可以在全局范圍內模擬瀏覽器JavaScript API,要完全了解何時執行定...
摘要:快速檢查可能告訴我們,簡單地從的域處理程序拋出將允許然后捕獲異常并執行其自己的錯誤處理程序,雖然情況并非如此,檢查后,你會看到堆棧只包含。 域模塊剖析 可用性問題 隱式行為 開發人員可以創建新域,然后只需運行domain.enter(),然后,它充當將來拋出者無法觀察到的任何異常的萬能捕捉器,允許模塊作者攔截不同模塊中不相關代碼的異常,防止代碼的發起者知道自己的異常。 以下是一個間接鏈...
摘要:避免使用最低公分母方法你可能想讓你的程序像最低公分母文件系統一樣,通過將所有文件名規范化為大寫,將所有文件名規范化為格式,并將所有文件時間戳標準化為秒分辨率,這是最小公分母的方法。 使用不同的文件系統 Node公開了文件系統的許多功能,但并非所有文件系統都相似,以下是建議的最佳實踐,以便在使用不同的文件系統時保持代碼簡單和安全。 文件系統行為 在使用文件系統之前,你需要知道它的行為方式...
閱讀 3682·2021-11-23 09:51
閱讀 1045·2021-11-19 11:30
閱讀 3373·2019-08-29 14:16
閱讀 3379·2019-08-29 12:12
閱讀 2374·2019-08-26 13:40
閱讀 3489·2019-08-26 12:21
閱讀 3082·2019-08-26 11:55
閱讀 2230·2019-08-26 11:35