PHP 轉 Node 筆記(二. 基礎的Web開發)

dmpty發表於2019-02-16

前言

上一篇文章主要以 PHP 的視角介紹了與 Node 之間的差異,這一篇來談談 Web Server 的搭建,Node 的 Web 框架有很多:express、koa 以及基於它們二次開發的框架等等,不過在本文中不使用框架,而是借鑑它們的思想完成 Web Server 原生上的實現

思路

先講一講在 Node 下做 Web 開發時與 PHP 的不同:

  • PHP 一般依靠 Apache 和 Nginx 做請求的轉發,它只負責業務邏輯和內容的輸出,而 Node 自身可以監聽埠接收請求,不過具體的解析工作 httphttps 模組已經完成了,和 PHP 的不同在於我們需要先引入這些模組再去寫業務邏輯。
  • Apache 與 Nginx 自帶了靜態檔案的處理,遇到 PHP 檔案時將請求轉發給處理 PHP 的模組,而 Node 相反,你可以直接處理請求,但需要自己開發處理靜態檔案的功能。當然你也可以使用已有的輪子,例如 serve-static

一個簡單的 Web 伺服器應該具有以下功能:

  • 處理靜態檔案
  • 將不同 URL 路由至對應的業務處理程式碼中

複雜一點的功能:

  • 中介軟體(攔截器)
  • 模板引擎
  • 與資料庫的互動(ORM)

本文只介紹前兩個功能的實現

建立一個 Http 服務

const http = require(`http`);
http.createServer((request, response) => {
    // 請求的入口
}).listen(8080);
複製程式碼

關於如何使用 requestresponse 物件完成一個請求響應,大多數教程裡都有提及,也可以去看 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

相關文章