過去 5 年,我先後在菜鳥網絡和螞蟻金服作開發工做,一方面支撐業務團隊開發各種業務系統,另外一方面在本身的技術團隊作基礎技術建設。期間藉着 Node.js 的鋒芒作了很多 Web 系統,有的至此生氣蓬勃、有的早已夭折淡出。在實踐中,螞蟻的 Chair 與淘系的 Midway 給了我很多啓發,也借鑑了很多 bad case。思考過身邊團隊、本身團隊、國外團隊的各類案例以後發現,搭建一個 Node.js 企業級 Web 服務器並不是難事,只是必須作好幾個關鍵事項。html
在接下來的一段時間裏,我會以如何 「從零搭建 Node.js 企業級 Web 服務器」 爲主題,將本身的所見所聞、所思所想詳盡地記錄下來,每一個章節最後會附上實現本章內容的源碼,但願能夠幫助正在學習和了解 Node.js 的朋友對 Web 服務器領域得到更清晰的理解和洞見。前端
閱讀提示:node
Node.js 發佈版本分爲 Current 和 LTS 兩類,前者每 6 個月迭代一個大版本,快速提供新增功能和問題修復,後者以 30 個月爲一個大週期,爲生產環境提供穩定依賴。當前 Node.js 最新 LTS 版本爲 12.18.2,本文以此版本做爲運行環境,能夠在官網下載並安裝。git
安裝完成後,在命令行輸入 node --version
查看輸出是否爲 v12.8.2
,若是一致,那麼安裝成功。github
另外,有興趣的讀者能夠嘗試經過 nvm / nvm-windows 管理多個 Node.js 版本,此處不是本文重點再也不展開。redis
Node.js 提供了本身的包管理器 npm,npm 默認從海外官方的 registry 拉取包信息速度比較慢,須要執行如下命令設置使用國內鏡像地址:docker
$ npm config set registry http://r.cnpmjs.org/
經過 npm 能夠全局或本地安裝依賴包,當本地安裝時 npm 會根據 package.json
安裝最新的依賴包,同時自動生成並更新 package-lock.json
文件,這就引起了一個問題:若是一個依賴包在 package.json
標記版本範圍內發佈了有問題的新版本,那麼咱們本身的項目也會跟着出問題。express
爲了解決這個問題,就引入了第三方包管理器 yarn,經過如下命令安裝:npm
$ npm i -g yarn
相比 npm,yarn 會嚴格按照自動生成的 yarn.lock
本地安裝依賴包,只有增刪依賴或者 package.json
標記版本發生不可兼容的變化時纔會更新 yarn.lock
,這就完全杜絕了上述 npm 的問題。考慮到企業級 Web 服務器對穩定性的要求,yarn 是必要的。編程
通常來說,作一個 Web 服務器會有兩種部署選擇,要麼是傳統的包部署,要麼是容器鏡像部署,後者較前者在編排上更方便,結合 Kubernetes 能夠作到很好的伸縮,是當前發展的趨勢。Docker 做爲主流容器技術必須熟練掌握,能夠在官網下載並安裝。
準備好了環境就能夠開始編碼了,先新建工程根目錄,而後進入並初始化 package.json
與目錄結構:
$ mkdir 00-static # 新建工程根目錄 $ cd 00-static # 進入工程根目錄 $ yarn init -y # 初始化 package.json yarn init v1.22.4 success Saved package.json $ mkdir src # 新建 src 目錄存放核心邏輯 $ mkdir public # 新建 public 目錄存放靜態資源 $ tree -L 1 # 展現當前目錄內容結構 . ├── package.json ├── public └── src
Express 與 Koa 均是 Node.js 服務端基礎框架。Express 發佈於 2010 年,憑藉出色的中間件機制在開源社區積累了大量的成熟模塊,如今是 OpenJS 基金會 At-Large 級別項目。Koa 發佈於 2013 年,相比 Express 具有了更加完善的中間件機制以及編程體驗,但在開源社區模塊積累的質與量上還有必定差距。在此比較幾個經常使用模塊:
模塊名稱 | 功能簡介 | Express / Koa | Star | Contributers | Used by | 最近提交時間 |
---|---|---|---|---|---|---|
passport | 認證登陸 | Express | 17.7k | 33 | 385k | 2020-06-10 |
koa-passport | 認證登陸 | Koa | 737 | 21 | 4.7k | 2019-07-13 |
connect-redis | 會話存儲 | Express | 2.3k | 51 | 26.3k | 2020-07-10 |
koa-redis | 會話存儲 | Koa | 310 | 13 | 2.7k | 2020-01-16 |
helmet | 網絡安全 | Express | 7.2k | 25 | 136.4k | 2020-07-11 |
koa-helmet | 網絡安全 | Koa | 546 | 24 | 4.1k | 2020-06-03 |
上表整理自 Github 截止 2020 年 7 月 20 日的數據。
相比 Koa 模塊,Express 模塊廣泛在星數(Star)、貢獻者數(Contributers)、使用數(Used by)上高出一個層次,同時 Express 模塊的貢獻者更熱心於維護與更新,Koa 儘管在國內受到過一些追捧,但在更全面的考量下 Express 纔是更穩健的選擇。在工程根目錄執行如下命令安裝:
$ yarn add express # 本地安裝 Express # ... info Direct dependencies └─ express@4.17.1 # ... $ tree -L 1 # 展現當前目錄內容結構 . ├── node_modules ├── package.json ├── public ├── src └── yarn.lock
如今能夠開始寫應用邏輯了,本章先作一個靜態資源服務器,以 public
目錄爲靜態資源目錄:
// src/server.js const express = require('express'); const { resolve } = require('path'); const { promisify } = require('util'); const server = express(); const port = parseInt(process.env.PORT || '9000'); const publicDir = resolve('public'); async function bootstrap() { server.use(express.static(publicDir)); await promisify(server.listen.bind(server, port))(); console.log(`> Started on port ${port}`); } bootstrap();
<!-- public/index.html --> <html> <head> <meta charset="utf-8" /> </head> <body> <h1>It works!</h1> </body> </html>
$ tree -L 2 -I node_modules # 展現除了 node_modules 以外的目錄內容結構 . ├── package.json ├── public │ └── index.html ├── src │ └── server.js └── yarn.lock
邏輯寫好以後在 package.json
中設置啓動腳本:
{ "name": "00-static", "version": "1.0.0", - "main": "index.js", + "scripts": { + "start": "node src/server.js" + }, "license": "MIT", "dependencies": { "express": "^4.17.1" } }
而後就能夠啓動應用了:
$ yarn start > Started on port 9000
訪問 http://localhost:9000/ 便可看到 index.html
內容:
接下來經過 Docker 對作好的靜態資源服務器進行容器化,新建如下配置文件:
# Dockerfile FROM node:12.18.2-slim WORKDIR /usr/app/00-static COPY . . RUN yarn EXPOSE 9000 CMD yarn start
# .dockerignore node_modules
$ tree -L 1 -a # 展現包括 . 開頭的所有目錄內容結構 . ├── .dockerignore ├── Dockerfile ├── node_modules ├── package.json ├── public ├── src └── yarn.lock
而後構建鏡像並啓動容器:
$ docker build -t 00-static:1.0.0 . # 構建容器鏡像,命名爲 00-static,標籤爲 1.0.0 # ... Successfully tagged 00-static:1.0.0 $ docker run -p 9090:9000 -d --name 00-static 00-static:1.0.0 # 以鏡像 00-static:1.0.0 運行容器,命名爲 00-static $ docker logs 00-static # 查看 00-static 容器的日誌 > Started on port 9000 $ docker stats 00-static # 查看 00-static 容器的狀態 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 43c451232fa5 00-static 0.03% 37.41MiB / 1.945GiB 1.88% 8.52kB / 3.35kB 0B / 0B 24
訪問 http://localhost:9090/ 便可與以前同樣看到 index.html
內容:
host1-tech/nodejs-server-examples - 00-static
從零搭建 Node.js 企業級 Web 服務器(零):靜態服務
從零搭建 Node.js 企業級 Web 服務器(一):接口與分層
從零搭建 Node.js 企業級 Web 服務器(二):校驗