從零搭建 Node.js 企業級 Web 服務器(零):靜態服務

前言

過去 5 年,我先後在菜鳥網絡和螞蟻金服作開發工做,一方面支撐業務團隊開發各種業務系統,另外一方面在本身的技術團隊作基礎技術建設。期間藉着 Node.js 的鋒芒作了很多 Web 系統,有的至此生氣蓬勃、有的早已夭折淡出。在實踐中,螞蟻的 Chair 與淘系的 Midway 給了我很多啓發,也借鑑了很多 bad case。思考過身邊團隊、本身團隊、國外團隊的各類案例以後發現,搭建一個 Node.js 企業級 Web 服務器並不是難事,只是必須作好幾個關鍵事項html

在接下來的一段時間裏,我會以如何 「從零搭建 Node.js 企業級 Web 服務器」 爲主題,將本身的所見所聞、所思所想詳盡地記錄下來,每一個章節最後會附上實現本章內容的源碼,但願能夠幫助正在學習和了解 Node.js 的朋友對 Web 服務器領域得到更清晰的理解和洞見。前端

閱讀提示:node

  • 本文着重表述 Web 後端技術相關內容,Web 前端內容採用 JavaScript Modules 進行演示。
  • 本文須要讀者具有基礎的編程能力以及對計算機網絡的基本瞭解,一些經常使用術語限於篇幅再也不展開。

準備環境

安裝 Node.js

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

安裝 Yarn

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 是必要的。編程

安裝 Docker

通常來說,作一個 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?

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 內容:

765bb72ad6058d32b641116e26f8d7338cf949f9.jpg

使用容器

接下來經過 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 內容:

e369752861fb54057d2683cca41c81eb01071368.jpg

本章源碼

host1-tech/nodejs-server-examples - 00-static

更多閱讀

從零搭建 Node.js 企業級 Web 服務器(零):靜態服務
從零搭建 Node.js 企業級 Web 服務器(一):接口與分層
從零搭建 Node.js 企業級 Web 服務器(二):校驗

相關文章
相關標籤/搜索