Node + Express 後臺開發 —— 上傳、下載和釋出

彭加李發表於2023-05-09

上傳、下載和釋出

前面我們已經完成了資料庫的增刪改查,在弄一個上傳圖片、下載 csv,一個最簡單的後臺開發就已完成,最後部署即可。

上傳圖片

需求

需求:做一個個人簡介的表單提交,有暱稱簡介頭像。後端能接收資料並儲存到資料庫。

接收不到資料

amis-editor(amis 低程式碼編輯器,更多瞭解請看這裡)繪製一個如下介面:

前端上傳檔案使用 InputFile 的手動上傳。配置如下:

{
    "type": "input-file",
    "name": "file",
    "label": "File",
    "accept": "*",
    "asBlob": true
}

後端定義一個路由:

// 個人簡介
// http://localhost:3000/users/upload
router.post('/upload', function(req, res, next) {
  console.log('req', req.body)
  res.send({"status":0,"msg":"","data":{}});
});

輸入資訊後提交,後端 req.body 是空物件,說明無法接收資料:

req {}
POST /users/upload 200 6.230 ms - 31

前端傳輸資料如下:

如果前端不傳檔案,後端 req.body 則能正常接收資料:

req { nickname: 'pjl', introduction: 'i am pjl', file: '' }
POST /users/upload 200 26.287 ms - 31

TipContent-Type 用於指示資源的 MIMIE 型別,請求中,客戶端告訴伺服器實際傳送的資料型別。相應中,告訴客戶端傳送的內容的內容型別。不傳檔案請求頭的 Content-Type 是 Content-Type: application/json;傳了檔案,請求頭的 Content-Type 是 Content-Type: multipart/form-data; boundary=----。需要在表單中進行檔案上傳時,就需要使用該格式:multipart/form-data

multer

Multer 是一個 node.js 中介軟體,用於處理 multipart/form-data 型別的表單資料,它主要用於上傳檔案。
:Multer 不會處理任何非 multipart/form-data 型別的表單資料

安裝 multer

PS E:\pjl-back-end> npm install --save multer

added 17 packages, and audited 119 packages in 18s

3 packages are looking for funding
  run `npm fund` for details

4 vulnerabilities (3 high, 1 critical)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

使用 multer:

PS E:\pjl-back-end> git diff routes/users.js

+const multer  = require('multer')
+// 啟動服務後,自動在 public 下建立 uploads 資料夾
+const upload = multer({ dest: 'public/uploads/' })

+// 一旦請求過來,就會先經過中介軟體把接收到的圖片存入 uploads 資料夾中,然後在到下一步
+// file 是前端檔案的 name。由於這裡是一張圖片,所以用 single 方法。多張圖片的使用請看文件
+router.post('/upload', upload.single('file'), function(req, res, next) {
+  // req.body 將具有文字域資料,如果存在的話
+  console.log(req.body)
+  // req.file 是 `file` 檔案的資訊
+  console.log(req.file)
   res.send({"status":0,"msg":"","data":{}});
 });

啟動服務後,會自動在 public 下建立 uploads 資料夾。輸入暱稱、簡介和頭像,點選提交。頭像檔案會重新命名並上傳到 uploads 中,透過 req.body 可以取得暱稱和簡介,透過 req.file 可以取得檔案資訊。後續存入資料庫的操作筆者就不在進行,無非就是透過 token 取得使用者 id,然後將暱稱、簡介和頭像路徑傳給 services,透過 model 儲存到資料庫。

Tip:雖然檔案沒有了字尾(.png),透過chrome 直接訪問圖片路徑(http://localhost:3000/uploads/36d8bda3160d8d09e81b167de1969b47)會自動下載,把圖片路徑給到 image 是可以正常使用。

下載csv

需求

需求:點選匯出全部按鈕,發起請求,透過後端直接下載 csv 檔案,裡面是表格資料。

實現

安裝 json2csv 包,用於將資料庫中查詢的 json 轉為 csv:

PS E:\pjl-back-end> npm install json2csv

added 4 packages, and audited 123 packages in 4s

3 packages are looking for funding
  run `npm fund` for details

4 vulnerabilities (3 high, 1 critical)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
PS E:\pjl-back-end>

安裝 iconv-lite 用於編碼轉換:

PS E:\pjl-back-end> npm i iconv-lite

added 2 packages, changed 1 package, and audited 125 packages in 3s

3 packages are looking for funding
  run `npm fund` for details

4 vulnerabilities (3 high, 1 critical)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

新建 utils.js,匯出 downloadResource 方法用於下載 csv:

// E:\pjl-back-end\libs\utils.js

const Parser = require('json2csv').Parser;

const downloadResource = (res, fileName, fields, data) => {
    
    const json2csv = new Parser({ fields });
    const csv = json2csv.parse(data);
    // iconv-lite: Pure JS character encoding conversion 轉碼,防止中文亂碼
    const iconv = require('iconv-lite');
    const newCsv = iconv.encode(csv, 'gbk')
  
    res.header('Content-Type', 'text/csv');
    res.attachment(fileName);
    return res.send(newCsv);
  }

  module.exports = {
    downloadResource,
  }

在任意路由中增加下載的處理請求:

const downloadResource = require('../libs/utils').downloadResource;
router.get('/download', function(req, res, next) {
  // 列名
  const fields = [
    {
      label: '姓名',
      value: 'name'
    },
    {
      label: '年齡',
      value: 'age'
    },
  ];
  // 模擬從資料庫查詢出的資料
  const data = [
    { "name":"peng 彭", "age": 18}, 
    { "name":"jia 加", "age": 19}, 
    { "name":"li 李", "age": 20}, 
    { "name":"pjl 彭加李", "age": 21}, 
  ];

  return downloadResource(res, 'users.csv', fields, data);
});

重啟服務,瀏覽器輸入 localhost:3000/users/download 回車後會自動下載 csv 檔案。雙擊開啟 csv,效果如下:

如果不轉碼處理,這裡 csv 中的中文就會亂碼。

疑惑:網上說 gbk和utf8都是都能編碼中英文。將 gbk 改為 utf8,在 win7 中開啟 csv 仍舊亂碼,或許是win7 中開啟csv是gbk,得保持客戶端和伺服器編碼一致?

釋出

pm2

假如 node 專案已經開發完畢,得將應用部署到伺服器中。

直接使用 node app.js 一旦關閉終端,服務就會中斷

雖然也可以使用 node app.js & 後臺啟動服務,但也有很多不足,比如重新發布程式碼不會自動生效

Tip: windows 下關閉後臺啟動的服務,比如埠是 3000

PS E:\pjl-back-end> netstat -ano|findstr 3000
  TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       12384
  TCP    [::]:3000              [::]:0                 LISTENING       12384
  TCP    [::1]:3000             [::1]:10229            TIME_WAIT       0
  TCP    [::1]:10230            [::1]:3000             TIME_WAIT       0
PS E:\pjl-back-end> taskkill /PID 12384 /F
成功: 已終止 PID 為 12384 的程式。

nodemon app.js 常用於開發環境

筆者這裡使用 pm2。有如下好處:

  • 監控服務資源
  • 釋出程式碼、當機後會自動重啟
  • 比如你的是cpu 是4核,也能充分利用
  • 能檢視日誌

體驗 pm2

全域性安裝 pm2

PS E:\pjl-back-end> npm install pm2 -g
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.

added 184 packages, and audited 185 packages in 25s

12 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS E:\pjl-back-end> pm2 list

下面我們使用 pm2 啟動服務:

Tip: 筆者由於環境問題,使用 npx 執行 pm2。你們可以省略。

檢視版本

透過 pm2 --version 檢視版本,說明安裝成功:

PS E:\pjl-back-end> npx pm2 --version
5.3.0
啟動服務

透過 pm2 start 入口檔案 啟動服務:

PS E:\pjl-back-end> npx pm2 start ./bin/www
[PM2] Starting E:\pjl-back-end\bin\www in fork_mode (1 instance)
[PM2] Done.
┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──
────────┬──────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──
────────┼──────────┤
│ 0  │ www    │ default     │ 0.0.0   │ fork    │ 9904     │ 0s     │ 0    │ online    │ 0%       │ 42.0mb   │ Adm… │ disabled │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──
────────┴──────────┘

應用的 id 是 0,name 是 www,後續刪除、啟動和重啟應用使用 id 和 name 都可以。

表示重啟次數為0。後續重啟應用會自動增加。

status 中的 online 表示已上線。

服務列表

透過 pm2 list 顯示應用列表,比如目前有一個服務(www)已啟動(online):

PS E:\pjl-back-end> npx pm2 list
┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──
────────┬──────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──
────────┼──────────┤
│ 0  │ www    │ default     │ 0.0.0   │ fork    │ 9904     │ 2m     │ 0    │ online    │ 0%       │ 57.9mb   │ Adm… │ disabled │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──
────────┴──────────┘
重啟服務

透過 pm2 restart id|name 重啟服務:

// 透過 id 重啟
PS E:\pjl-back-end> npx pm2 restart 0
Use --update-env to update environment variables
[PM2] Applying action restartProcessId on app [0](ids: [ '0' ])
[PM2] [www](0) ✓
┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──
────────┬──────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──
────────┼──────────┤
│ 0  │ www    │ default     │ 0.0.0   │ fork    │ 12088    │ 0s     │ 1    │ online    │ 0%       │ 41.9mb   │ Adm… │ disabled │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──
────────┴──────────┘
// 透過 name 重啟
PS E:\pjl-back-end> npx pm2 restart www
Use --update-env to update environment variables
[PM2] Applying action restartProcessId on app [www](ids: [ 0 ])
[PM2] [www](0) ✓
┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──
────────┬──────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──
────────┼──────────┤
│ 0  │ www    │ default     │ 0.0.0   │ fork    │ 6648     │ 0s     │ 2    │ online    │ 0%       │ 40.9mb   │ Adm… │ disabled │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──

Tip: 表示重啟過幾次了

應用詳情

pm2 info www 檢視 www 這個應用的詳細資訊:

PS E:\pjl-back-end> npx pm2 info www
 Describing process with id 0 - name www 
┌───────────────────┬────────────────────────────────────────────────┐
│ status            │ online                                         │
│ name              │ www                                            │
│ namespace         │ default                                        │
│ version           │ 0.0.0                                          │
│ restarts          │ 2                                              │
│ uptime            │ 62s                                            │
│ script path       │ E:\pjl-back-end\bin\www                      │
│ script args       │ N/A                                            │
│ error log path    │ C:\Users\Administrator\.pm2\logs\www-error.log │
│ out log path      │ C:\Users\Administrator\.pm2\logs\www-out.log   │
│ pid path          │ C:\Users\Administrator\.pm2\pids\www-0.pid     │
│ interpreter       │ node                                           │
│ interpreter args  │ N/A                                            │
│ script id         │ 0                                              │
│ exec cwd          │ E:\pjl-back-end                              │
│ exec mode         │ fork_mode                                      │
│ node.js version   │ 16.20.0                                        │
│ node env          │ N/A                                            │
│ watch & reload    │ ✘                                              │
│ unstable restarts │ 0                                              │
│ created at        │ 2023-05-09T07:28:11.550Z                       │
└───────────────────┴────────────────────────────────────────────────┘
 Revision control metadata 
┌──────────────────┬──────────────────────────────────────────┐
│ revision control │ git                                      │
│ remote url       │ N/A                                      │
│ repository root  │ E:\pjl-back-end                        │
│ last update      │ 2023-05-09T07:28:12.179Z                 │
│ revision         │ a02f7d6427fde5fdce41aff1626d31c19d80fcdf │
│ comment          │ 取消資料庫和登入標識                               │
│ branch           │ master                                   │
└──────────────────┴──────────────────────────────────────────┘
 Actions available 
┌────────────────────────┐
│ km:heapdump            │
│ km:cpu:profiling:start │
│ km:cpu:profiling:stop  │
│ km:heap:sampling:start │
│ km:heap:sampling:stop  │
└────────────────────────┘
 Trigger via: pm2 trigger www <action_name>

 Code metrics value 
┌────────────────────────┬───────────┐
│ Used Heap Size         │ 20.15 MiB │
│ Heap Usage             │ 89 %      │
│ Heap Size              │ 22.64 MiB │
│ Event Loop Latency p95 │ 2.04 ms   │
│ Event Loop Latency     │ 0.08 ms   │
│ Active handles         │ 4         │
│ Active requests        │ 0         │
└────────────────────────┴───────────┘
 Divergent env variables from local env 


 Add your own code metrics: http://bit.ly/code-metrics
 Use `pm2 logs www [--lines 1000]` to display logs
 Use `pm2 env 0` to display environment variables
 Use `pm2 monit` to monitor CPU and Memory usage www
監控應用

透過 pm2 monit id|name 監控應用程式:

PS E:\pjl-back-end> npx pm2 monit www
┌─ Process List ───────────────────────── ─  www Logs   ─────────────────┐┌─ Logs ───────────────────────────────────────────────
 [ 0] www                        Mem:  59 MB    CPU:  0 %  online  │www > 錯誤資訊
│                                                                 │www > GET /users/testlog 304 1.186 ms - -
│                                                                 │www > 資訊
│                                                                 │www > 錯誤資訊
│                                                                 │www > GET /users/testlog 304 1.837 ms - -
│                                                                 │www > 資訊
│                                                                 │www > GET /users/testlog 304 0.914 ms - -
│                                                                 │www > 錯誤資訊
│                                                                 │www > 資訊
│                                                                 │www > 錯誤資訊
│                                                                 │www > GET /users/testlog 304 1.369 ms - -
│                                                                 │www > 資訊
│                                                                 │www > 錯誤資訊
│                                                                 │www > GET /users/testlog 304 1.733 ms - -
│                                                                 │www > 資訊
│                                                                 │www > 錯誤資訊
│                                                                 │www > GET /users/testlog 304 3.095 ms - -                                                                                                                
└─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────
┌─ Custom Metrics ────────────────────────────────────────────────┐┌─ Metadata ──────────────────────────────────────────────
│Used Heap Size                                       20.94 MiB   │App Name              www                                                                                                                                
│Heap Usage                                             91.45 %   │Namespace             default
│Heap Size                                            22.89 MiB   │Version               0.0.0
│Event Loop Latency p95                                 9.12 ms   │Restarts              2
│Event Loop Latency                                     0.14 ms   │Uptime                2m
└─────────────────────────────────────────────────────────────────┘└────────────────────────────────────────────
 left/right: switch boards | up/down/mouse: scroll | Ctrl-C: exit                                                                                                                       To go further check out https://pm2.io/

Tip:日誌資訊也會同步輸出,日誌就是console.log 或 console.error輸出的內容,下文配置 pm2會講到。

停止應用

透過 pm2 stop id|name 停止服務:

PS E:\pjl-back-end> npx pm2 stop www
[PM2] Applying action stopProcessId on app [www](ids: [ 0 ])
[PM2] [www](0) ✓
┌────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──
────────┬──────────┐
│ id │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──
────────┼──────────┤
│ 0  │ www    │ default     │ 0.0.0   │ fork    │ 0        │ 0      │ 2    │ stopped   │ 0%       │ 0b       │ Adm… │ disabled │
└────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──
────────┴──────────┘
關閉並刪除應用

透過 pm2 delete id|name 關閉並刪除應用:

PS E:\pjl-back-end> npx pm2 delete www
[PM2] Applying action deleteProcessId on app [www](ids: [ 0 ])
[PM2] [www](0) ✓
┌────┬───────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────
┬──────────┬──────────┐
│ id │ name      │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
└────┴───────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────
┴──────────┴──────────┘
穩定的服務

比如筆者寫一個如下服務 app2.js:

// app2.js
const http = require('http')
const fs = require('fs')
const server = http.createServer()

const requestListener = (req, res) => {
    const url = req.url
    // 如果url是 '/',則返回主頁
    if(url === '/'){
        res.end("home page")
    }else if(url === '/b'){
        res.end("page b")
    }else if(url === '/error'){
        throw new Error('故意報錯')
    }
}

server.on('request', requestListener)
server.listen('3000', () => {
    console.log('伺服器已啟動')
})

透過 node app2.js 啟動服務後,訪問 localhost:3000/error 故意報錯,服務就會死掉,無法在響應其他請求:

PS E:\pjl-back-end> node app2.js
伺服器已啟動
E:\pjl-back-end\app2.js:13
        throw new Error('故意報錯')
        ^

Error: 故意報錯
    at Server.requestListener (E:\pjl-back-end\app2.js:13:15)
    at Server.emit (node:events:513:28)
    at parserOnIncoming (node:_http_server:998:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)

如果改用 pm2 啟動服務:

PS E:\pjl-back-end> npx pm2 start app2.js
[PM2] Starting E:\pjl-back-end\app2.js in fork_mode (1 instance)
[PM2] Done.
┌────┬─────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬─
─────────┬──────────┐
│ id │ name    │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼─────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼─
─────────┼──────────┤
│ 0  │ app2    │ default     │ 0.0.0   │ fork    │ 12248    │ 0s     │ 0    │ online    │ 0%       │ 40.2mb   │ Adm… │ disabled │
└────┴─────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴─
─────────┴──────────┘

再次訪問 localhost:3000/error,透過 pm2 list 發現重啟()次數從0變成了3,總之是重啟了:

PS E:\pjl-back-end> npx pm2 list
┌────┬─────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬─
─────────┬──────────┐
│ id │ name    │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼─────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼─
─────────┼──────────┤
│ 0  │ app2    │ default     │ 0.0.0   │ fork    │ 12196    │ 25s    │ 3    │ online    │ 0%       │ 39.7mb   │ Adm… │ disabled │
└────┴─────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴─

訪問 http://localhost:3000/ 頁面顯示 home page,說明服務正常,也較之前更穩定。

配置 pm2

需求

需求:配置應用名稱入口檔案監控日誌例項數

程式碼

專案根目錄新建 pm2 配置檔案 pm2.config.json

{
    "apps": {
        // 應用名稱
        "name": "spug-back-end",
        // 入口檔案
        "script": "./bin/www",
        // 監控。修改程式碼後自動生效
        "watch": true,
        // 排除某些檔案的監控
        "ignore_watch": [
            "node_modules",
            "logs"
        ],
        // 錯誤日誌。透過 console.error() 輸出
        "error_file": "logs/error.log",
        // 自定義日誌。透過 console.log() 輸出
        "out_file": "logs/custom.log",
        // 給日誌新增時間。否則你得這麼寫 console.log('資訊...', '2023-05-09 16:25:00')
        // YYYY不要小寫
        "log_date_format": "YYYY-MM-DD HH:mm:ss",
        // cpu 核數。不要超過伺服器的 cpu 核數
        // 筆者 cpu 核數是 2,這樣會啟動 2 個服務,能更好的利用伺服器資源。
        "instances": 2
    }
}

Tip:windows 檢視 CPU 核數 - 在 cmd 命令中輸入 wmic,然後在出現的新視窗中輸入 cpu get NumberOfCores

PS E:\pjl-back-end> wmic
wmic:root\cli>cpu get NumberOfCores
NumberOfCores
2

修改 package.json(pm2 指定配置檔案啟動服務):

// package.json
"scripts": {
    "start": "nodemon ./bin/www",
   +"pro": "pm2 start ./pm2.config.json"
  },

增加如下路由,用於測試日誌

// localhost:3000/users/testlog
router.get('/testlog', function(req, res, next) {
  // 輸出到自定義日誌中
  console.log('資訊');
  // 輸出到錯誤日誌中
  console.error('錯誤資訊');
  res.send({"status":0,"msg":"123","data":{}});
});
測試

透過 npm run pro 啟動服務:

PS E:\pjl-back-end> npm run pro

> pjl-back-end@0.0.0 pro
> pm2 start ./pm2.config.json

[PM2][WARN] Applications spug-back-end not running, starting...
[PM2] App [spug-back-end] launched (2 instances)
┌────┬──────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬───
───────┬──────────┬──────────┐
│ id │ name             │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼──────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼───
───────┼──────────┼──────────┤
│ 0  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 12496    │ 0      │ 1    │ stopped   │ 0%       │ 0b       │ Adm… │ enabled  │
│ 1  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 11436    │ 0      │ 1    │ stopped   │ 0%       │ 0b       │ Adm… │ enabled  │
└────┴──────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴───
───────┴──────────┴──────────┘

// 啟動後立刻執行
PS E:\pjl-back-end> npx pm2 list
┌────┬──────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬───
───────┬──────────┬──────────┐
│ id │ name             │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼──────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼───
───────┼──────────┼──────────┤
│ 0  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 1396     │ 14s    │ 1    │ online    │ 0%       │ 58.7mb   │ Adm… │ enabled  │
│ 1  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 1704     │ 14s    │ 1    │ online    │ 0%       │ 58.7mb   │ Adm… │ enabled  │
└────┴──────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴───
───────┴──────────┴──────────┘
PS E:\pjl-back-end>

應用名是 spug-back-end

啟動了兩個應用,說明 "instances": 2 已生效。

logs 資料夾中生成了4個日誌檔案(每個cpu核就是兩個),檔名也是我們配置的,目前日誌內容都為空:

$ ll logs
total 0
-rw-r--r-- 1 Administrator 197121 0 May  9 16:40 custom-0.log
-rw-r--r-- 1 Administrator 197121 0 May  9 16:40 custom-1.log
-rw-r--r-- 1 Administrator 197121 0 May  9 16:40 error-0.log
-rw-r--r-- 1 Administrator 197121 0 May  9 16:40 error-1.log

訪問 http://localhost:3000/ 頁面顯示正常:

Express
Welcome to Express

再次檢視日誌發現 custom-1.log 有內容,記錄了著請求的詳細資訊。例如時間、請求的資源(/stylesheets/style.css):

Administrator@3L-WK-10 MINGW64 /e/pjl-back-end (master)
$ ll logs
total 1
-rw-r--r-- 1 Administrator 197121   0 May  9 16:40 custom-0.log
-rw-r--r-- 1 Administrator 197121 144 May  9 16:42 custom-1.log
-rw-r--r-- 1 Administrator 197121   0 May  9 16:40 error-0.log
-rw-r--r-- 1 Administrator 197121   0 May  9 16:40 error-1.log

Administrator@3L-WK-10 MINGW64 /e/pjl-back-end (master)
$ cat logs/custom-1.log
2023-05-09 16:42:35: GET / 304 21.595 ms - -
2023-05-09 16:42:35: GET /stylesheets/style.css 304 3.358 ms - -

修改某請求響應:

$ git diff  routes/index.js

 router.get('/', function(req, res, next) {
-  res.render('index', { title: 'Express' });
+  res.render('index', { title: 'Express2' });
 });

再次訪問 http://localhost:3000/ 修改資訊自動生效:

Express2
Welcome to Express2

透過 npx pm2 list 發現服務自動重啟了(↺ 1 -> 3):

PS E:\pjl-back-end> npx pm2 list
┌────┬──────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬───
───────┬──────────┬──────────┐
│ id │ name             │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼──────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼───
───────┼──────────┼──────────┤
│ 0  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 13868    │ 89s    │ 3    │ online    │ 0%       │ 60.5mb   │ Adm… │ enabled  │
│ 1  │ spug-back-end    │ default     │ 0.0.0   │ cluster │ 11792    │ 89s    │ 3    │ online    │ 0%       │ 61.1mb   │ Adm… │ enabled  │
└────┴──────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴───

再次檢視日誌,發現 custom-0.log 也有資料了,這裡其實間接說明了一個負載均衡的問題,這兩個應用都能提供服務。

$ ll logs
total 2
-rw-r--r-- 1 Administrator 197121 228 May  9 16:46 custom-0.log
-rw-r--r-- 1 Administrator 197121 144 May  9 16:42 custom-1.log
-rw-r--r-- 1 Administrator 197121   0 May  9 16:40 error-0.log
-rw-r--r-- 1 Administrator 197121   0 May  9 16:40 error-1.log

接著訪問輸出日誌的請求:http://localhost:3000/users/testlog,發現在同一時刻(16:54:47)往 custom-0.log 輸出了 資訊,在 error-0.log 中輸出了 錯誤資訊:

$ git diff logs
--- a/logs/custom-0.log
+++ b/logs/custom-0.log
 2023-05-09 16:53:56: GET /users/testlog 304 14.507 ms - -
+2023-05-09 16:54:47: 資訊
+2023-05-09 16:54:47: GET /users/testlog 304 9.892 ms - -

--- a/logs/error-0.log
+++ b/logs/error-0.log
 2023-05-09 16:53:56: 錯誤資訊
+2023-05-09 16:54:47: 錯誤資訊

相關文章