小程序成长之路(五)-- 深入腾讯云(代码分析)

533 阅读4分钟

上一篇主要总结了环境搭建的流程及在过程中遇到的坑,这一篇详细研究下小程序和服务器通信间的原理。

先分析下上图中三个实验代码:

1. https:

小程序只支持 https 访问,想访问 https 一定是要在自己的服务器上配置证书的,小程序成长之路(四)-- 深入腾讯云(环境搭建) ,中有详细说明,这里就不多赘述。

小程序有自己调用接口的方法 wx.request

 //this.data.url 为 https://www.winsonye.club/hello
   wx.request({
        url: this.data.url,
        method: 'GET',
        success: (res) => {
           
        },
        //下面省略
    });

服务器端:

// 实现一个中间件,对于未处理的请求,都输出 "Response from express"
app.use((request, response, next) => {
    response.write('Response from express');
    response.end();
});

2. 会话

以前web端的开发,都是通过cookie中存储sessionid,在每次请求时带上cookie 中存储的信息来保持会话,但是小程序不支持cookie, 需要自己实现会话,我们来看下如何实现:

微信小程序客户端腾讯云增强 SDK

上面字面是不是很不好理解 ?说白了就是在客户端文件中引入一个官方提供的文件:wafer-client-sdk/index 然后在代码中引用:

const wafer = require('../../vendors/wafer-client-sdk/index');

wx.request 换做 wafer.request 小程序的网络请求就会包含会话。

注意:

在使用 wafer.request 前要设置登陆地址:

wafer.setLoginUrl(`https://` + config.host + '/login');

然后进行登陆操作:

qcloud.login({
    success: function (userInfo) {
        console.log('登录成功', userInfo);
    },
    fail: function (err) {
        console.log('登录失败', err);
    }
});

或者省略此步,直接在 wafer.request 中设置 login: true

wafer.request({
    //request 方法也支持 login 参数支持在请求之前自动登录
    login: true,
    url: this.data.url,
    method: 'GET',
    success: (res) => {},
});

注意:

这里有个小坑说一下: wx.getUserInfo() 调用这个方法获取用户信息时,之前会在小程序上自动弹出授权窗口,但是现在改了,这个方法依然可以使用,但是不会自动弹出授权窗口了。

就是说, 以前没有授权的情况下,调用方法,自动弹出授权窗口,授权后拿到用户信息,完美!而现在,调用时会先给你提示,点击继续使用直接报错!!

如何解决呢?

在页面上加上授权按钮 <button open-type="getUserInfo">授权</button>,点击授权弹出授权弹窗,确认授权后在调用wx.getUserInfo(),返回正常。

回到正题,接着上面客户端发送请求的方法 wafer.request 准备好后,看下服务端需要准备的:

  1. wafer-node-session: 引用 wafer-session 支持小程序会话(服务端)
  2. connect-mongo:使用 MongoDB 作为会话的存储
// 引用 wafer-session 支持小程序会话
const waferSession = require('wafer-node-session'); 
// 使用 MongoDB 作为会话的存储
const MongoStore = require('connect-mongo')(waferSession); 
......//省略无关代码
// 独立出会话中间件给 express 和 ws 使用
const sessionMiddleware = waferSession({
    appId: config.appId,
    appSecret: config.appSecret,
    loginPath: '/login',
    store: new MongoStore({
        url: `mongodb://${config.mongoUser}:${config.mongoPass}@${config.mongoHost}:${config.mongoPort}/${config.mongoDb}`
    })
});
app.use(sessionMiddleware);

// 在路由 /me 下,输出会话里包含的用户信息
app.use('/me', (request, response, next) => { 
    response.json(request.session ? request.session.userInfo : { noBody: true }); 
    if (request.session) {
        console.log(`Wafer session success with openId=${request.session.userInfo.openId}`);
    }
}); 

前后端准备完毕,点击发送请求,看下返回结果:

上述返回结果中已经带有用户信息,会话信息产生!!

3. websocket

先跟大家分析一下微信支持 WebSocket 的原因(摘自--微信小程序云端解决方案探索之路)。

传统的 HTTPS 连接请求,每个请求都需要建立一次连接,耗费比较多的资源。同时微信有最大连接数的限制(5个),所以实时通信的需求不好做,长连接的方案也只能串行传输,这种方案耗电高体验差。

当我们把目光转向 WebSocket 之后,会发现 WebSocket 通信全程只需要建立一次连接,就可以实现双向的实时通信,更省电的情况下获得更好的体验。

这就是小程序支持 WebSocket 的一个重要原因,可以提高业务的体验并增加续航。

客户端:

  • 微信小程序客户端是有一套websocket的方法的: websocket
  1. wx.connectSocket 建立链接
  2. wx.sendSocketMessage 发送信息
  3. wx.onSocketOpen 监听WebSocket连接打开事件
  4. wx.onSocketMessage 监听服务器返回信息

。。。等等

服务端:

  • 需要引入 ws 模块。

监听客服端触发的事件:

  1. ws.on('connection', function() {...})
  2. ws.on('message', function() {...})
  3. ws.on('close', function() {...})

发送信息:

  1. ws.send('xxxxxxx')
// 引入 ws 支持 WebSocket 的实现
const ws = require('ws');

// 导出处理方法
exports.listen = listen;

/**
 * 在 HTTP Server 上处理 WebSocket 请求
 * @param {http.Server} server
 * @param {wafer.SessionMiddleware} sessionMiddleware
 */
function listen(server, sessionMiddleware) {
    // 使用 HTTP Server 创建 WebSocket 服务,使用 path 参数指定需要升级为 WebSocket 的路径
    const wss = new ws.Server({ server, path: '/ws' });

    // 监听 WebSocket 连接建立
    wss.on('connection', (ws,request) => {// 要升级到 WebSocket 协议的 HTTP 连接

        // 被升级到 WebSocket 的请求不会被 express 处理,
        // 需要使用会话中间节获取会话
        sessionMiddleware(request, null, () => {
            const session = request.session;
            if (!session) {
                // 没有获取到会话,强制断开 WebSocket 连接
                ws.send(JSON.stringify(request.sessionError) || "No session avaliable");
                ws.close();
                return;
            }
            // 保留这个日志的输出可让实验室能检查到当前步骤是否完成
            console.log(`WebSocket client connected with openId=${session.userInfo.openId}`);
            serveMessage(ws, session.userInfo);
        });
    });

    // 监听 WebSocket 服务的错误
    wss.on('error', (err) => {
        console.log(err);
    });
}

/**
 * 进行简单的 WebSocket 服务,对于客户端发来的所有消息都回复回去
 */
function serveMessage(ws, userInfo) {
    // 监听客户端发来的消息
    ws.on('message', (message) => {
        console.log(`WebSocket received: ${message}`);
        ws.send(`Server: Received(${message})`);
    });

    // 监听关闭事件
    ws.on('close', (code, message) => {
        console.log(`WebSocket client closed (code: ${code}, message: ${message || 'none'})`);
    });

    // 连接后马上发送 hello 消息给会话对应的用户
    ws.send(`Server: 恭喜,${userInfo.nickName}`);
}

通过客服端和服务端相互监听消息事件,进行信息传输。

到这里,https请求,会话websocket,的源码已经分析完毕,用到了wafer的客户端会话服务和websocket, 完成功能。但是好像没有用到wafer信道服务服务端的会话服务

未完待续。。。