Node.js 系列 - 搭建 "Hello World" HTTP 伺服器

罐裝汽水_Garrik發表於2018-10-29

作為還在漫漫前端學習路上的一位自學者。我以學習分享的方式來整理自己對於知識的理解,同時也希望能夠給大家作為一份參考。希望能夠和大家共同進步,如有任何紕漏的話,希望大家多多指正。感謝萬分!


在這一節, 我會先介紹 "客戶端" 和 "伺服器" 的概念.

然後我會簡單介紹一下 "HTTP 協議".

最後, 我們要試著搭建一個最簡易的 HTTP 伺服器. 當瀏覽器去向這個伺服器傳送請求的時候, 伺服器會返回 "Hello World" 文字.

客戶端 & 伺服器

先思考, 平時我們在瀏覽器位址列中, 輸入網址按下回車之後, 網頁是如何呈現在我們面前的?

很顯然, 我們想要訪問的網頁不是原本就儲存在我們的電腦裡的. 我們在瀏覽器中輸入網址, 去網頁檔案所在的網路裝置中去請求網頁. 擁有網頁的網路設別同意了我們的請求, 把網頁返回給了瀏覽器. 之後瀏覽器再解析渲染網頁檔案, 使網頁最終能呈現在我們面前.

像瀏覽器這樣, 請求訪問文字或影象等資源的一端稱為客戶端,而提供資源響應的一端稱為服務端

什麼是 HTTP 協議

MDN HTTP 文件

客戶端和伺服器之間是怎麼交流資訊, 傳遞資料的呢?

網路之間的各種網路裝置, 就像 "學校裡說不同方言的同學", 大家想要交流就必須使用 "普通話". 各種網路設別之間想要通訊也需要一套大家都認可的通訊標準.

HTTP 協議 (Hyper Text Transfer Protocol 超文字傳輸協議)就是 伺服器 和 客戶端 之間的通訊規則.

在應用 HTTP 協議時,必定是一端擔任客戶端角色,另一端擔任伺服器端角色

使用 HTTP 協議傳輸的資訊叫做 HTTP 報文. 請求端(客戶端)的 HTTP 報文叫做請求報文,響應端(伺服器端)的叫做響應報文。 HTTP 報文可分為 報文首部報文主體 兩塊, 中間由一個空行分開.

Untitled Diagram(2)

請求報文 & 響應報文

『 請求報文組成 』: 請求方法 + 請求 URI + HTTP 協議版本 + (可選的請求首部欄位 和 內容實體)

Node.js 系列 - 搭建 "Hello World" HTTP 伺服器

『 響應報文組成 』: HTTP 協議版本 + 狀態碼(表示請求成功或失敗的數字程式碼)+ 用以解釋狀態碼的原因短語 + (可選的響應首部欄位 以及 實體主體)

Node.js 系列 - 搭建 "Hello World" HTTP 伺服器

『 請求方法 』:

MDN - HTTP 請求方法 文件

HTTP 定義了一組請求方法, 以表明要對給定資源執行的操作。

常用的有:

  • GET: 用來請求伺服器端指定的資源。使用 GET 的請求應該只用於獲取資料。
  • POST: 用來傳送資料給伺服器. 雖然用 GET 方法也可以傳輸主體. 但一般不用 GET 方法進行傳輸,而是用 POST 方法。
  • PUT: 用於新增資源. PUT 與 POST 方法的區別在於,PUT 方法呼叫一次與連續呼叫多次是等價的,而連續呼叫多次 POST 方法可能會有副作用,比如將一個訂單重複提交多次。
  • DELETE: 用於刪除指定的資源。

除上面這些之外, 還有其他請求方法, 想了解可以自行查閱文件.

『 URI 』:

HTTP 協議使用 URI 定位網際網路上的資源。也就是我們常說的 "網址". 多數情況下 URL 和 URI 說的是一回事. 這裡不做過多論述.

下圖是 URI 的各個組成部分

2824193-3b10e5ce8796c938

『 狀態碼 』:

MDN - HTTP 狀態碼 - 文件

狀態碼的職責是當客戶端向伺服器端傳送請求時,描述伺服器返回的請求結果。

藉助狀態碼,使用者可以知道伺服器端是正常處理了請求,還是出現了錯誤。

狀態碼由 3 位數字 和 原因短語 組成。

數字中的第一位指定了響應類別,後兩位無分類。響應類別有以下 5 種:

Screen Shot 2018-09-26 at 4.31.44 PM

最常見的兩個就是:

  • 200 OK: 表示從客戶端發來的請求在伺服器端被正常處理了。
  • 404 Not Found: 該狀態碼錶明伺服器上無法找到請求的資源。除此之外,也可以在伺服器端拒絕請求且不想說明理由時使用。

其餘的狀態碼, 大家可以查閱文件, 這裡就不介紹了.

『 首部欄位 』:

MDN - HTTP 首部欄位 - 文件

首部欄位, 為客戶端和伺服器, 處理請求和響應, 提供了所需要的資訊。

HTTP 首部欄位是由 首部欄位名 和 欄位值 構成的,中間用 : 分隔。

例如:

在 HTTP 首部中以 Content-Type 這個欄位來表示報文主體的型別。 Content-Type: text/html 就是說, 報文主體的型別為 HTML.

更多首部欄位我就不再這裡介紹了, 大家可以根據需要查閱文件.

使用 HTTP 模組 實現一個 "Hello World" 伺服器

HTTP 模組 - 文件

Node.js 自身提供的 http 模組, 提供了 HTTP 伺服器和客戶端介面, 可以很便捷地應用 HTTP 協議.

下面我就介紹如何用 http 模組實現一個響應 "Hello World" 給客戶端的 Web 伺服器:

首先, 新建一個 JavaScript 檔案, 取名 myServer.js , 當然你可以叫別的.

在檔案開頭先引用 http 模組.

var http = require('http');
複製程式碼

然後呼叫 http.createServer 函式建立並返回一個 HTTP 伺服器. 這個函式接收一個回撥函式作為引數. 伺服器每次收到客戶端發過來的 HTTP 請求會交給這個回撥函式處理. 回撥函式會受到兩個引數, "請求物件" 和 "響應物件", 一般簡寫為 reqres.

var server = http.createServer(function(req, res) {
    // 處理請求, 送出響應
});
複製程式碼

伺服器每次收到新的請求, 都會建立新的請求物件和響應物件. 從客戶端發過來的請求報文會被解析, 然後作為請求物件的一部分. 在回撥函式的內部, 你需要根據業務邏輯處理請求, 然後送出響應給客戶端, 結束此次請求.

在本練習中, 我們要返回給客戶端一個寫有 "Hello World" 的純文字. 在回撥函式中我們需要用到三個響應物件上的函式:

  • res.writeHead(statusCode[, statusMessage][, headers]): 該方法會傳送一個響應頭給客戶端. 第一個引數作為狀態碼, 最後一個引數 headers 是響應頭物件。 第二個引數 statusMessage 是可選的狀態描述。
  • res.write(chunk[, encoding][, callback]): 該方法會傳送一塊響應主體。 它可被多次呼叫,以便提供連續的響應主體片段。第一個引數是一個字串或一個 Buffer 位元組流, 如果是字串的話, 第二個引數指定如何將它編碼成一個位元組流 (預設為 utf-8). 最後一個引數這裡先不考慮.
  • res.end([data][, encoding][, callback]): 該方法會通知伺服器,所有響應頭和響應主體都已被髮送,即伺服器將其視為已完成。每次響應都必須呼叫這個方法來結束請求, 否則請求會被一直掛起. 如果傳入 data 引數, 相當於呼叫 res.write(data, encoding).

那麼根據需求我們知道:

  • 響應成功, 狀態碼為 200.
  • 響應回去的為純文字, 需要設定響應頭 Content-Type 的值為 text/plain.
  • 響應回去的主體是一個字串 "Hello World".

根據這兩個資訊, 我們就可以很輕鬆的寫出請求處理函式內的程式碼:

var server = http.createServer(function(req, res) {
    res.writeHead(200, {'Content-Type':'text/plain'});
    res.write("Hello World");
    res.end();
});
複製程式碼

最後, 我們需要給 Web 伺服器繫結一個埠. 為了讓伺服器可以提供多種服務, 不同請求會被髮送到不同的埠. 只有傳送到我們指定埠的 HTTP 請求會被上面的程式碼所處理.

我們使用 server.listen 函式, 第一個引數為埠號, 最後一個引數是一個回撥函式, 監聽成功後呼叫.

在這裡我用 3000 作為埠號, 當然你也可以改成你喜歡的.

server.listen(3000, function() {
    console.log("伺服器啟動成功!");
    console.log("正在監聽 3000 埠:");
});
複製程式碼

全部寫完後程式碼為:

var http = require('http');

var server = http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write("Hello World");
    res.end();
});

server.listen(3000, function() {
    console.log("伺服器啟動成功!");
    console.log("正在監聽 3000 埠:");
});
複製程式碼

在命令列中輸入 node myServer.js ( 注意你的路徑和檔名 )

伺服器執行後, 可以在命令列看見

Screen Shot 2018-09-26 at 6.10.47 PM

然後在瀏覽器中登入 localhost:3000, 你就可以看見伺服器響應給你的 "Hello World" 了.

Screen Shot 2018-09-26 at 6.11.52 PM

現在你成功的返回了一條純文字內容給客戶端. 接下來, 你可以試著返回一個 HTML 文字嗎?

Tip: Content-Type 的值應改成什麼?


? 好啦,今天的分享就告一段落啦。下一篇中,我會介紹如何實現一個 "HTTP 靜態檔案伺服器"。

傳送門 - Node.js 系列 - 搭建靜態資源伺服器

如果喜歡的話就點個關注吧!O(∩_∩)O 謝謝各位的支援❗️

相關文章