轻松理解小程序 session的实现
panda-chat-room
小程序版 websocket 聊天室。 从服务器到小程序客户端配置基础教程。
在本教程内我们将在小程序内实现一个基本的 websocket 聊天室, 计划实现以下功能:
- 微信用户登录「 小程序 session 管理 」:ballot_box_with_check:
- 用户间文本交流 「 websocket 实现 」:ballot_box_with_check:
- 用户间发送图片等富媒体信息 「 文件的储存及相关逻辑 」:ballot_box_with_check:
小程序已挂,原因是个人开发者无法提交信息交流类小程序, 不过在本地运行 demo 还是没问题的。
写的有纰漏的地方还请大家指出,我们一起进步 ^o^
聊天室基础配置
小程序端的聊天室信息流其实非常简单, 而本教程就借助一个好玩儿的小程序聊天室来进一步理解小程序中的 session 实现。
我在服务器端环境搭建及配置主要参考腾讯云实验 基于 CentOS 搭建微信小程序服务
我们在此先要理解小程序端为何无法实现 session, 以及如何在小程序实现 websocket 通信。
小程序并非嵌套在微信内的 html5 网页, 它并不是从 url 访问到的。 我们只能自己实现类似会话的东西, 好在官方已经提供了相应的套件来实现 session。 即 wafer-client-sdk 和 node 中间件 wafer-node-session , 我们依照文档就能简单地实现 session。
腾讯云 wafer 项目下有很多相似项目「大部分需要配合腾讯云进行一键部署」, 如果我们只需要实现小程序 session 管理的话, wafer-client-sdk 和 node 中间件 wafer-node-session 即可。
在服务器端我们使用了 ws 包来实现 websocket ,没有使用 socket.io 的原因是 socket.io 需要客户端有额外的脚本才能实现通信。
在小程序端我们引入 wafer-client-sdk 套件使服务器可以获取 session。
主要逻辑分为几个简单函数, 当然你需要先配置请求的服务器域名和小程序账号密码。
// 引入 session 套件, 里面封装了 wx.login, wx.getUserInfo 等操作
const wafer = require('../../vendors/wafer-client-sdk/index')
// 用于登录使服务器获得 session, 然后服务器返回的 session 里就会包含用户信息了, 用来在 websocket 里返回发信息用户的头像 url
function login(){
.....
}
// 用于有新信息时更新数据, msg 指信息, ad 指 websocket 传回的信息 id, 用于 scroll-into-view 滚动
pushMsg(msg, ad) {
.....
}
// 用于监听 websocket 连接
listen(){
.....
}
// 用于小程序发送 websocket 信息
send(){
.....
}
基本就是这些, 关于 websocket 通信过程是这样的:
客户端发送信息给服务器 m1
服务器收到信息后根据条件返回给客户端 m2
每个客户端收到 m2 后更新视图
当然最开始是要与服务器端 websocket 连接的, 只有每个连接了的客户端才可以交流信息。
小程序 session 解析
对于 session 的实现我们在服务器端使用了 wafer-node-session 即为连接提供 session 能力。 在小程序端我们配套使用了 wafer-client-sdk , 这里面封装了 wx.request、 wx.login 等逻辑, 实现了小程序端的用户登录、session 设置。
关于小程序端的 session 获取问题主要有如下几个步骤
wx.login 获取 code
wx.request 发送 code 给自己的服务器
服务器收到 code 配合 appId 和 appSecret 发送给微信服务器换取 openId 和 sessionKey
wx.getUserInfo 会得到 rawData、signature、encryptedData、 iv, 我们需要把它们发送到自己服务器。 我们构建自己的 signature2 = sha1(sessionKey + rawData) , 比对 signature 和 signature2 就完成了数据校验
服务端通过 aes-128-cbc 算法对称解密 encryptedData 和 iv 然后得到 userInfo 这次得到的 userInfo 里还包含 openId 等信息 「如果在微信开放平台绑定小程序就会得到 unionId」
服务端构建 req.session 对象并返回给小程序,里面包含 id、 userInfo、 sessionKey「小程序传到服务器的」、skey 「服务器自己根据sessionKey + appId + appSecret 生成, 有过期时间」。 而我们自己生成的 skey 是有设置过期时间的, 但小程序端的 session 也有自己的过期时间 「应该是微信按使用小程序的频率来动态设置过期时间的。 wafer 会自动调用 wx.checkSession 检查是否过期, 过期了就 wx.login」。
在我们的 demo 中就出现了服务器 session 已经过期而本地 session 还没过期的情况。 而 websocket 每次发送信息都需要从 req.session 内获取用户头像, 所以会导致 websocket 连接失败。 但是在小程序端 session 未过期,即在服务器端的 sessionKey 和小程序的 sessionKey 不一致了 「客户端 sessionKey 还在而服务器的 sessionKey 已经过期销毁」, 导致比对失败。 那怎么办呢? 重新请求呗! 但是因为 wafer 封装了 session 管理 「小程序端 session 过期后才会重新请求」 存在 session 缓存的缘故, 小程序并没有重新发送信息给自己的服务器进而生成新的 sessionKey, 所以我们在每一次 wx.sendSocketMessage 发信息的时候都要检查服务器端的 session 情况, 这里需要做简单的判断「websocket 信息有错误就清除本地 session」让小程序重新请求服务器。
websocket 信息发送
既然要发送信息「即产生数据」, 那么这些信息都储存在哪里呢? 在发送文本信息时, 服务器端收到数据后只做简单地处理便返回给小程序, 这时的数据应该是储存在服务器内存中。 因为 websocket 在收到请求后简单处理了字符串信息直接返回给小程序, 那我们发送其它富媒体信息时,也可以以二进制的方式发送给 websocket 服务器, 然后重新返回给客户端 「即 websocket 只做文件中转」,相关实现 websocket-stream 。 貌似看起来很复杂,在这里我使用了国内的 paas 服务商 leanCloud 的储存服务 「即小程序端把发送的文件储存在云端,返回一个文件地址」,然后我们把这个文件信息进行标注「即只发送文件的 url 信息, 小程序端判断请求是否是文件进而显示」。 当然你也可以发送视频或者音频, 把他们都保存在云端, 只发送其相应的 url 即可。 我们这里的 websocket 服务器只做一个文件中转的功能, 而文件的存储交给云端来负责。
panda-chat-room 项目源码
项目源码 :https://github.com/hiscc/panda-chat-room
- Golang插入排序
- Golang写的并行排序算法
- Go中调用dll示例
- python 序列化数据:pickle与json ,dumps与loads
- golang继承,和多态
- python 利用random生成验证码与MD5码加密过程
- Java内部类的继承
- Java继承类中static成员函数的重写
- Search for a range寻找上下界-Leetcode
- Basic Calculator 基本计算器-Leetcode
- python yield函数深入浅出理解
- 十分钟搞定 Tensorflow 服务
- datapump跨平台升级迁移的总结 (r8笔记第77天)
- Java中isAssignableFrom()方法与instanceof()方法用法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android端“被挤下线”功能的单点登录实现
- Android轻松实现多语言的方法示例
- Android开发实现去除bitmap无用白色边框的方法示例
- Android开发实现的内存管理工具类
- Android日期和时间选择器实现代码
- Android开发实现ImageView加载摄像头拍摄的大图功能
- Android开发实现的Intent跳转工具类实例
- Android开发中的文件操作工具类FileUtil完整实例
- Android开发中超好用的正则表达式工具类RegexUtil完整实例
- Android ijkplayer的使用方法解析
- Android开发实现查询远程服务器的工具类QueryUtils完整实例
- 解决android studio 3.0 加载项目过慢问题–maven仓库选择
- Android实现朋友圈点赞列表
- Kotlin基本类型自动装箱一点问题剖析
- Kotlin入门教程之开发环境搭建