前言
上一篇文章主要以 PHP 的視角介紹了與 Node 之間的差異,這一篇來談談 Web Server 的搭建,Node 的 Web 框架有很多:express、koa 以及基於它們二次開發的框架等等,不過在本文中不使用框架,而是借鑑它們的思想完成 Web Server 原生上的實現
思路
先講一講在 Node 下做 Web 開發時與 PHP 的不同:
- PHP 一般依靠 Apache 和 Nginx 做請求的轉發,它只負責業務邏輯和內容的輸出,而 Node 自身可以監聽埠接收請求,不過具體的解析工作
http
與https
模組已經完成了,和 PHP 的不同在於我們需要先引入這些模組再去寫業務邏輯。 - Apache 與 Nginx 自帶了靜態檔案的處理,遇到 PHP 檔案時將請求轉發給處理 PHP 的模組,而 Node 相反,你可以直接處理請求,但需要自己開發處理靜態檔案的功能。當然你也可以使用已有的輪子,例如 serve-static
一個簡單的 Web 伺服器應該具有以下功能:
- 處理靜態檔案
- 將不同 URL 路由至對應的業務處理程式碼中
複雜一點的功能:
- 中介軟體(攔截器)
- 模板引擎
- 與資料庫的互動(ORM)
本文只介紹前兩個功能的實現
建立一個 Http 服務
const http = require(`http`);
http.createServer((request, response) => {
// 請求的入口
}).listen(8080);
複製程式碼
關於如何使用 request
與 response
物件完成一個請求響應,大多數教程裡都有提及,也可以去看 Node 中文文件,在此不做詳細介紹
處理靜態檔案
這裡我們使用 serve-static,使用 npm 安裝這個模組,在專案根目錄下建立 public 資料夾並放入一些靜態頁面,建立 index.js 檔案:
const http = require(`http`);
const serveStatic = require(`serve-static`);
const publicPath = `public`;
const staticHandler = serveStatic(publicPath);
http.createServer((request, response) => {
staticHandler(request, response, () => {
// 失敗回撥
})
}).listen(8080);
複製程式碼
以上程式碼是處理靜態檔案最簡單的配置,要注意的是 staticHandler()
是一個非同步操作,使用 Node 執行 index.js 就能夠訪問 public 目錄下的檔案了
簡單的路由
要實現路由我們首先得獲取到請求路徑,引入 Node 內建的 url
模組可以幫我們解決這個問題
const url = require(`url`);
const http = require(`http`);
http.createServer((request, response) => {
const path = url.parse(request.url).pathname;
if (path === `/`)
response.end(`path is /`);
else if (path === `/index`)
response.end(`path is /index`);
else {
response.statusCode = 404;
response.end(`Not Found`);
}
}).listen(8080);
複製程式碼
這是一個最簡單的路由實現,要注意的是一定要保證任何情況都要呼叫 response.end()
來終止請求,不然瀏覽器會一直處於等待相應的狀態
在實際開發中我們不會使用一連串的 if...else
來處理路由,一般是建立一張路由對映表,再加上靜態檔案處理:
const url = require(`url`);
const http = require(`http`);
const serveStatic = require(`serve-static`);
const publicPath = `public`;
const staticHandler = serveStatic(publicPath);
const map = new Map([
[`/`, response => {
response.end(`path is /`);
}],
[`/index`, response => {
response.end(`path is /index`);
}]
]);
http.createServer((request, response) => {
const path = url.parse(request.url).pathname;
if (map.has(path)) {
let handler = map.get(path);
handler(response);
} else
staticHandler(request, response, () => {
response.statusCode = 404;
response.end(`Not Found`);
});
}).listen(8080);
複製程式碼
現在服務的處理邏輯為:先查詢對應的路由,有則交給路由的回撥處理,沒有則去查詢 public 目錄下的靜態檔案,都沒有則返回404錯誤
結語
還以為本系列還會再寫幾篇,但發現越寫到後面和 PHP 越沒關係,所以打算放棄這個字首,以後的文章也會專注於 Node 的 Web 開發
感謝閱讀,文中錯誤歡迎指出,歡迎交流
後面幾篇文章將會基於我最近在擼的開源框架 varal 來介紹更加複雜一點的後端架構,求關注,求 Star