在yog2框架中自建模塊,以實現socket.io與express共享session中間件

czmdzx 8年前發布 | 22K 次閱讀 Socket 中間件 JavaScript開發 Socket.IO

來自: http://segmentfault.com/a/1190000004392232

導引

最近遇到了一個需要在yog2框架中增加websocket服務的案子,此文主要講在案子過程中碰到的一些問題和解決方案

由于此文和yog2這個框架高度相關,如需了解yog2請移步 https://github.com/fex-team/yog2

yog2 是一個專注于 Node.js UI 中間層的應用框架。它基于 express 和 fis 開發,在享受 express 的靈活擴展能力和 fis 強大的前端工程化能力的同時,引入了自動路由、app 拆分以及后端服務管理模塊來保證UI中間層的快速開發與穩定可靠。

我的做法

需要在yog框架中增加websocket服務,我的做法是在yog的入口文件 yog/app.js 中將socket.io服務器綁定在原有express的server上(也可以綁定在新端口如8081上,看你喜歡),然后在 別處[1] 進行業務邏輯和路由

[1] :別處的意思是將業務代碼最好放在別的文件夾里,這個根據你們的項目自己決定

我遇到的問題

socket.io服務器的中間件(主要是解析/驗證session的那個)需要重新去寫,當前項目使用配置過的 express-session 中間件完成對session的解析,這完全是重復造輪子

對此問題我的想法

讓socket.io服務器共享express的中間件!

此文答案一 啟發,可以將 express-session 模塊定義的中間件提出來給socket.io用。

但是問題來了,yog2已經對中間件的擺放位置進行了一下處理,主要在 yog/conf/plugins/http.js 內實現(見下文結構樹,或見 官方文檔 ),如何將已定義的中間件提出來呢?

解決方案

新建自己的session解析中間件模塊 mysession ,在yog2的結構樹中的擺放位置如下

├── yog
    ├── app                    
    ├── conf                
    │    ├── plugins                
    │    │    ├── http.js
    │    │    ├── dispatcher.js
    │    │    ├── log.js
    │    │    ├── view.js
    │    │    ├── mysession.js    - mysession模塊的配置文件
    ├── plugins                    
    │    ├── mysession            
    │    │    ├── index.js        - mysession模塊文件
    ├── static
    ├── views
    └── app.js

模塊文件放置入 yog/plugins/mysession/index.js ,詳見 用戶插件相關文檔

module.exports.mysession = function(app, conf){
    return function(){
        app.use(conf);
    };
};

那么坑來了, 官方文檔 里說

app為yog.app對象,即Express的app

conf為插件的配置項

module.exports后的屬性名就是插件的真實名稱

app 參數解釋很清楚,那么 conf 參數是啥呢?!

通過安裝 中間件文檔末尾 中提到的session模塊

yog2 plugin install session

我發現,這個 conf 參數將從 yog/conf/plugins/你的模塊名.js 中export的變量中獲取。

一個字,坑!

于是照葫蘆畫瓢,將 mysession 模塊的配置文件放置入 yog/conf/plugins/mysession.js

(你可以用你自己的session解析模塊,比如 connect-memcached 也可以,此處用 session-file-store )

// example using session-file-store to store session
var maxAge = 30 * 24 * 3600 * 1000;
var ttl = maxAge / 1000;
var sessionFileStoreGenerator = require('session-file-store');
var SessionFileStore = sessionFileStoreGenerator(session);
sessionStore = new SessionFileStore({ ttl: ttl });
var conf = session({
    secret: 'mysession-key',
    store: sessionStore,
    resave: false,
    saveUninitialized: true,
    cookie: {
        maxAge: maxAge
    }
});
module.exports.mysession = conf;

最后在 yog/conf/plugins/http.js 中加入這個自定義中間件

// ...
module.exports.http = {
     middleware: [
         // ...
         'views',
         'methodOverride',
         'mysession', //加入我的新中間件
         'dispatcher',
         'notFound',
         'error',
         // ...
     ]
};
// ...

至此,已完成將session解析中間件提取出來,剩下的就是如 此文答案一 中提到的,使用如下代碼共用這個中間件

sio.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res, next);
});

具體實現代碼如下:編輯入口文件 yog/app.js

var yog = require('yog2-kernel');

// 此處載入這個共享的session解析中間件
var sessionMiddleware = require('./conf/plugins/mysession.js').mysession;

var app = yog.bootstrap({
    rootPath: __dirname
}, function(){

    var server = yog.server = app.listen(process.env.PORT || 8080);

    // 以下是為socket.io新加入的代碼

    // 此處綁定在express的server實例上,你也可以綁定一個新端口
    var sio = require('socket.io')(server); 
    sio.use(function(socket, next) {
        sessionMiddleware(socket.request, socket.request.res, next);
    });
    require('../你的socket.io業務邏輯處理與路由代碼文件')(sio);

    // 以上是為socket.io新加入的代碼

});

結語

當然,我對自己的這些解決方案也不是完美認同,比如:

  • 編輯入口文件某些情況下并不是best practice,也可以在別處啟動socket服務。

  • 通過改變yog2的已有架構來使其更好的支持代碼重用

  • 在入口文件中引用模塊也是一個很糟糕的做法,有沒有更優雅的做法呢?

對于在yog2內使用socket的問題、共享中間件的問題等,一定還有更好的解決方案,所以在此拋磚引玉一下,大家都會怎么做?

更多興趣閱讀

在探索的過程中,讀到一篇好答案,關于express的session解析模塊的sign機制。

感興趣的請移步 Why is it insecure to store the session ID in a cookie directly?

 本文由用戶 czmdzx 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!