背景知識
我們知道後端是通過session
來維持使用者的會話的,每當使用者發起一個請求的時候,使用者的瀏覽器就會將使用者的一個sessionID
以cookie
的形式傳送到後端,後端接收到這個sessionID
後,就會看記憶體中有沒有sessionID
為此sessionID
的session
,如果存在,則授權訪問;否則重定向到授權頁面或者返回錯誤碼。
因為是NodeJS
是單執行緒的,為了充分利用CPU
的多核特性,採用了cluster
模組,利用主從模式,生成與CPU
核心數量相當的子程式,然後主程式用來捕獲請求隨機分配給子程式處理,並負責子程式的崩潰重啟。但是,在引進了cluster
模組之後,以前的session
認證機制將完全不可用。原因如下:
我們知道程式與程式之間是不能共享資料的,所以程式1的記憶體資料無法被程式2讀取到,所以如果使用者A認證的過程是被程式1所處理的,那麼維持會話的
session
將儲存在程式1的記憶體資料中;如果此使用者接下的請求被程式2所處理,因為程式2沒有處理過使用者A的認證,沒有維持這個會話的session
,所以程式2會判斷使用者A並沒有授權。這樣使用者A需要多次重複認證訪問才能繼續下去…
解決方案
我們現在的問題是session
無法共享,所以我們可以想辦法讓session
共享。通過將session
存在基於記憶體的資料庫redis
裡面,即可完美的解決了session
共享的問題。
現在以Express
框架為例,說一下具體做法:
- 安裝
redis
,安裝過程參考 官方文件 - 安裝
connect-redis
模組
1npm install -save connect-redis - 配置
Express
123456789101112// 僅列出核心程式碼var express = require("express");var session = require("express-session");var RedisStore = require('connect-redis')(session);var config = require("./config");var app = express();app.use(session({saveUninitialized: true,resave: true,secret: config.sessionSecret,store: new RedisStore() // 利用redis儲存session}));
後記
其實,我們也可以換一種思路來解決這個問題。既然多程式之間無法共享session
,那就索性不共享唄!放棄cluster
,利用系統指令碼開啟與CPU
數量相當的NodeJS
程式,並且每個程式監聽不同的網路埠,利用Nginx
負載均衡機制,設定均衡模式為ip_hash
,這樣對於同一個客戶端的請求轉發到同一個埠,避免了將請求轉發到沒有認證的埠,這樣也可以解決此問題。
基本思想如下圖所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
+-------------------+ | | +-----> 127.0.0.1:3000 | | | | | +-------------------+ +---------------+ | +----------------+ | +---+ +-------------------+ | | | | | | | user A +------> +---------> 127.0.0.1:3001 | | | | | | | +----------------+ | | +-------------------+ | NGINX | +----------------+ | | +-------------------+ | | | | | | | user B +------> +---------> 127.0.0.1:3002 | | | | | | | +----------------+ | +----+ +-------------------+ +---------------+ | | +-------------------+ | | | +----> 127.0.0.1:3003 | | | +-------------------+ |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式