踩過微信小程序坑的人都知道,微信小程序是不支持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:以上爲項目部分代碼,不保證可以徹底運行。