您现在的位置: 微信小程序 > 微信小程序开发 > 教程 >

微信小程序session管理

来源:微信小程序 编辑:Yiyongtong.com 发布时间:2018-02-10 11:31热度:


最近微信小程序开发很火。我们的移动端项目也开始使用小程序来实现,在这之前我们已经基于Html5实现了类似于小程序的应用。了解了小程序开发后觉得有很多相似之处,还是要用到js和css这些技术。但也有许多不同,jquery等这些js库不能直接使用了、http session也不支持、页面发起http请求小程序有自己的api。

对于我们项目来说就不只是简单的将H5页面翻译成小程序的页面这么简单了。首先要解决的问题就是http session。在H5项目中,使用http session来关联微信openid这样每次http请求都能确定是哪个用户发起的请求。如果熟悉http session的原理,session问题就好解决了。常见的session保持方式是,当浏览器向服务端发起http请求时,服务端检查在http 头部cookie参数里是否包含sessionid,如果有sessionid就根据sessionid去查看存储在服务器端的session,session里保存的当前会话的一些信息。如果sessionid没有服务端就会分配一个,写到cookie字段里,浏览器下次发起其它请求的时候带上。而在小程序里所有的请求都通过wx.request API来发起的。如果对wx.request API包装一下,使其每次向服务端发起请求时也添加一个名称为Cookie的http header,这样也不用对服务端作改动。服务端分配的sessionid使用wx.setStorageSync API存储在微信客户端。

 

1、客户端实现 
客户端代码目录smallapp-session/views,客户端主要实现对wx.request的封装,在wafer-client-demo项目的基础上作了一些修改。 
wx.request封装

 

  1. 最近微信小程序开发很火。我们的移动端项目也开始使用小程序来实现,在这之前我们已经基于Html5实现了类似于小程序的应用。了解了小程序开发后觉得有很多相似之处,还是要用到js和css这些技术。但也有许多不同,jquery等这些js库不能直接使用了、http session也不支持、页面发起http请求小程序有自己的api。
    
    对于我们项目来说就不只是简单的将H5页面翻译成小程序的页面这么简单了。首先要解决的问题就是http session。在H5项目中,使用http session来关联微信openid这样每次http请求都能确定是哪个用户发起的请求。如果熟悉http session的原理,session问题就好解决了。常见的session保持方式是,当浏览器向服务端发起http请求时,服务端检查在http 头部cookie参数里是否包含sessionid,如果有sessionid就根据sessionid去查看存储在服务器端的session,session里保存的当前会话的一些信息。如果sessionid没有服务端就会分配一个,写到cookie字段里,浏览器下次发起其它请求的时候带上。而在小程序里所有的请求都通过wx.request API来发起的。如果对wx.request API包装一下,使其每次向服务端发起请求时也添加一个名称为Cookie的http header,这样也不用对服务端作改动。服务端分配的sessionid使用wx.setStorageSync API存储在微信客户端。
    
    项目源码地址:https://github.com/it-man-cn/smallapp-session
    
    1、客户端实现 
    客户端代码目录smallapp-session/views,客户端主要实现对wx.request的封装,在wafer-client-demo项目的基础上作了一些修改。 
    wx.request封装
    
    var constants = require('./constants');
    var utils = require('./utils');
    var Session = require('./session');
    var loginLib = require('./login');
    var noop = function noop() {};
    var buildAuthHeader = function buildAuthHeader(session) {
        var header = {};
        if (session && session.id) {
            header['Cookie'] =constants.WX_HEADER_ID+'='+session.id;
        }
        return header;
    };
    function request(options) {
        if (typeof options !== 'object') {
            var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
            throw new RequestError(constants.ERR_INVALID_PARAMS, message);
        }
        var requireLogin = options.login;
        var success = options.success || noop;
        var fail = options.fail || noop;
        var complete = options.complete || noop;
        var originHeader = options.header || {};
        // 成功回调
        var callSuccess = function () {
            success.apply(null, arguments);
            complete.apply(null, arguments);
        };
        // 失败回调
        var callFail = function (error) {
            fail.call(null, error);
            complete.call(null, error);
        };
        // 是否已经进行过重试
        var hasRetried = false;
        if (requireLogin) {
            doRequestWithLogin();
        } else {
            doRequest();
        }
        // 登录后再请求
        function doRequestWithLogin() {
            loginLib.login({ success: doRequest, fail: callFail });
        }
        // 实际进行请求的方法
        function doRequest() {
            var authHeader = buildAuthHeader(Session.get());
            console.log(authHeader)
            wx.request(utils.extend({}, options, {
                header: utils.extend({}, originHeader, authHeader),
                success: function (response) {
                    var data = response.data;
                    console.log("err:",data)
                    console.log("errid:",data[constants.WX_SESSION_MAGIC_ID])
                    // 如果响应的数据里面包含 SDK Magic ID,表示被服务端 SDK 处理过,此时一定包含登录态失败的信息
                    if (data && data[constants.WX_SESSION_MAGIC_ID]) {
                        console.log("clear session")
                        // 清除登录态
                        Session.clear();
                        var error, message;
                        if (data.error === constants.ERR_INVALID_SESSION) {
                            // 如果是登录态无效,并且还没重试过,会尝试登录后刷新凭据重新请求
                            if (!hasRetried) {
                                hasRetried = true;
                                doRequestWithLogin();
                                return;
                            }
                            message = '登录态已过期';
                            error = new RequestError(data.error, message);
                        } else {
                            message = '鉴权服务器检查登录态发生错误(' + (data.error || 'OTHER') + '):' + (data.message || '未知错误');
                            error = new RequestError(constants.ERR_CHECK_LOGIN_FAILED, message);
                        }
                        callFail(error);
                        return;
                    }
                    callSuccess.apply(null, arguments);
                },
                fail: callFail,