基於Node.js的微信小程序cookie解決方案

         踩過微信小程序坑的人都知道,微信小程序是不支持cookie的。微信小程序採用的是wx.login獲取code,經過開發者服務器端同微信服務器進行數據交互實現登陸。獲得openid或者unionid與本地數據庫關聯,從而獲得登陸用戶相關信息。html

         具體參考微信相關文檔wx.login,這裏不贅述。前端

         一般狀況下,咱們不單單是須要用戶數據,還須要用戶的登陸狀態,也就是session和cookie機制。要命的是小程序不支持cookie,沒有了cookie,session也無從談起。這裏基於node.js的express和koa,經過header頭添加標記的方式,模擬cookie,從而在服務器端引入session。node

         cookie的本質是惟一字符串標記,由瀏覽器自動生成(這裏是做爲會話方案,而非數據存儲方案而言)。既然是惟一字符串標記,那咱們也能夠本身生成一個相似的標記,添加到Headers頭中,相似這樣git

let header={'x-xxxx-cookie':'uuid cookie'};
//
wx.request({
    url:url,
    data:data,
    header:header,
    method:method,
    success: function( res ) {
        
    },
    fail: function( error ) {
    
    }
});

         須要注意的是,這裏的uuid cookie最好使用服務器端的session ID,後面再說爲何?github

         以上就是前端(小程序端)的處理,接下來是服務器端的處理,服務器端使用的是express或者koa,具體使用請移步:
         Express
         Koaredis

         服務器端Express中session使用的是express-session,Koa中使用的是koa-generic-session,對於Koa這裏多說一句,本來也打算使用koa-session,最後放棄選擇了前者,由於後者沒有暴露出相似獲取session ID的參數,而整個過程當中須要獲取到session ID很是重要。session存儲都使用Redis。
Express部分代碼以下:數據庫

var express = require('express');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var RedisStore = require('connect-redis')(session);

//
var sessionStore=new RedisStore({
    host:config.redis.host,
    port:config.redis.port
});
var app = express();
//
app.use(cookieParser());

//cookie
var cookieParser=cookieParser(config.secret);
app.use(cookieParser);

//session
var sessionParser = session({
    store:sessionStore,
    secret:config.secret,
});
app.use(sessionParser);    

//

Koa部分代碼:express

const Koa  = require('koa');
const session = require('koa-generic-session');
//const session = require('koa-session');
const RedisStore = require('koa-redis');
//
const app = new Koa();

// middlewares
app.use(bodyparser({
  enableTypes:['json', 'form', 'text']
}));
//
let sessionStore=new RedisStore(sessionRedisOptions);
let sessionOptions={
    store: sessionStore,
    key: '',
};
//
const sessionParser = session(sessionOptions,app);
app.use(sessionParser);

         獲取session ID,Express中能夠直接經過req.sessionID獲取獲得,koa中使用ctx.sessionId獲取獲得。之因此session ID重要,主要是咱們能夠直接經過它獲取到session。若是不使用session ID的方式的話,咱們須要本身額外去存儲相關數據,能夠不用將數據掛載到req.session或者ctx.session上,會帶來額外的代碼成本。並且萬一哪天微信小程序支持cookie了呢,採用session ID方式,仍是和之前同樣操做session數據。json

         咱們須要將session ID從服務器端返回到小程序端,一般會在第一個請求的時候就返回,而後小程序端將該數據保存,相似這樣:小程序

app.globalData.cookieID=uuid cookie;//uuid cookie爲服務器端返回的session ID

         小程序端之後的請求都將該數據添加到Headers頭中傳遞到服務器端。

         服務器端下一個請求,直接經過req.session或者ctx.session仍是獲取不到以前設置的session數據啊!
         的確是的,咱們須要在路由以前,添加一箇中間件來解決。相似這樣:
Express部分代碼:

app.use(function(req,res,next){
    //
    var sessionID=req.headers['x-xxxx-cookie'];
    if(sessionID){
        //
        return sessionStore.get(sessionID,function(err,session){
            //
            req.session=Object.assign(req.session||{},session||{});
            //
            next();
        });
    }
    //
    next();
});

Koa部分代碼:

app.use(async function (ctx,next){
    //
    var cookies=ctx.cookies;
    var sessionID=ctx.request.headers['x-xxxx-cookie']||cookies.get(sessionOptions.key);
    if(sessionID){
        //
        let sess= await ctx.sessionStore.get(sessionID);
        //
        let session=Object.assign(ctx.session||{},sess||{});
        ctx.session=session;
    }
    //
    await next();
});

         也就是咱們須要經過session ID獲得session,而後賦值到req.session或者ctx.session上,保證以後能夠直接按照普通方式操做session數據。

         好了,就到這裏,總結一下:
         經過header添加類cookie惟一字符串標記,而該字符串標記直接對應服務器端session ID,能夠在服務器端直接經過session ID獲取到session數據,利用中間件將獲取到的session數據賦值給request,從而實現小程序端就像支持cookie同樣。

         若是引入了socket,好比ws,箇中過程又要複雜一些,額外引入其餘坑須要填埋,下回再表。

PS:以上爲項目部分代碼,不保證可以徹底運行。

相關文章
相關標籤/搜索