微信小程序源码解析

最近在写小程序,转载一些别人的文章,学习下经验。

学以致用123 
2018.05.09 13:46 字数 1536 阅读 475评论 0

关键字:微信小程序登录、login、request、getuserinfo

本文是对使用 wafer2 实现登录的分析,对使用 wafer2 框架的小程序适用,不涉及 腾讯云音视频登录功能外的其它功能。

参考:https://github.com/tencentyun/wafer2-client-sdk

简介

腾讯云音视频小程序的 demo 代码使用的是腾讯云 wafer2 框架。

wafer2 简化了用户登录方法,在 app.js 中设置 qcloud 的 LoginUrl 然后调用 qcloud.login 或者使用 login 参数设置为 true 的 qcloud.request 请求即可。

这里先贴出经过下面分析得出的使用 qcloud 的 login 和 request 的方法。

首先,在 app.js 中设置 qcloud 的 LoginUrl :

qcloud.setLoginUrl(config.url + 'login');

如果只需要后台实现登录请求,那么使用 qcloud.login:

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

setLoginUrl 中设定的 url 的后台视图需要解析 login 的 GET请求的请求头获得code、encryptedData 和 iv ,返回的响应至少需要包含 code,如果成功执行,code 需要设为 0 而且还需要返回 data ,data 中至少需要包含 skey 、userinfo 和 iminfo 三项内容。

如果后台请求之前需要自动登录,那么使用 qcloud.request :

qcloud.setLoginUrl(myloginUrl);
qcloud.request({
    login: true,
    url: myUrl,
    success: function (response) { console.log(response); }, fail: function (err) { console.log(err); } }); 

注意,qcloud.request 通过构造请求头向后台传送数据。

下面的内容是具体代码分析。

现有代码分析

demo 代码并没有使用 wafer2 内置的登录函数,而是在与 config.js 同一个目录下的 getloginInfo.js 中通过 wx.login 和 wx.getUserInfo 实现登录的。这里的实现代码为:

// 获取微信登录信息,用于获取openid
function getLoginInfo(options) { wx.login({ success: function (res) { if (res.code) { console.log('获取code成功',res.code); options.code = res.code; // 获取用户信息 wx.getUserInfo({ withCredentials: false, success: function (ret) { options.userName = ret.userInfo.nickName; proto_getLoginInfo(options); }, fail: function() { proto_getLoginInfo(options); } }); } else { console.log('获取用户登录态失败!' + res.errMsg); options.fail && options.fail({ errCode: -1, errMsg: '获取用户登录态失败,请退出重试' }); } }, fail: function (res) { console.log('获取用户登录态失败!' + res.errMsg); if (ret.errMsg == 'request:fail timeout') { var errCode = -1; var errMsg = '网络请求超时,请检查网络状态'; } options.fail && options.fail({ errCode: errCode || -1, errMsg: errMsg || '获取用户登录态失败,请退出重试' }); } }); } 

这里的代码逻辑非常清晰,用流程图表示是这样的:


 
getlogininfo_wxlogin.jpg

上述流程中 wx.login 及 wx.getUserInfo 的详细信息请查看官网文档。

代码执行成功会调用 proto_getLoginInfo 函数,如果失败,则运行调用输入参数的失败处理函数。

proto_getLoginInfo 在 getLoginInfo 的下面,主要实现腾讯云的 RoomService 登录功能,但是由于 RoomService 登录需要传入后台计算得到的用户签名,这里使用了 wx.request 向后台发送 GET 请求,发送请求的具体代码为:

function proto_getLoginInfo(options) { wx.request({ url: config.serverUrl + '/weapp/utils/get_login_info', data: { userIDPrefix: 'weixin', code: options.code }, method: 'GET', header: { 'content-type': 'application/json' // 默认值 }, success: function (ret) { if (ret.data.code) { console.log('获取登录信息失败,调试期间请点击右上角三个点按钮,选择打开调试'); options.fail && options.fail({ errCode: ret.data.code, errMsg: ret.data.message + '[' + ret.data.code + ']' }); return; } console.log('获取IM登录信息成功: ', ret.data); ... }, fail: function (ret) { console.log('获取IM登录信息失败: ', ret); if (ret.errMsg == 'request:fail timeout') { var errCode = -1; var errMsg = '网络请求超时,请检查网络状态'; } options.fail && options.fail({ errCode: errCode || -1, errMsg: errMsg || '获取登录信息失败,调试期间请点击右上角三个点按钮,选择打开调试' }); } }); } 

这里的 wx.request 向后台发送 code 参数,后台使用 code 换取 openid 然后计算用户签名,代码中的登录功能结束。

然而, wafer2 的处理用户登录流程是这样的:

 
wxlogin.png

由于这里指向后台传入了 code ,所以后台只能实现红色框中的内容。前台也没有实现紫色框中的保存会话功能。

我们可以将 wx.getUserInfo 的 withCredentials 设置为 true ,然后为 wx.request 传入 encryptedData 和 iv ,完成上图中后台的工作,并使用 wx.setStorageSync(KEY,DATA) 保存会话。

然而,我们完全可以使用 wafer2 内置函数实现登录。

使用 wafer2 内置函数实现登录

查看 app.js 文件,我们可以看到:

var qcloud = require('./lib/index');

App({
  onLaunch: function () { // 展示本地存储能力 // qcloud.setLoginUrl(config.url + 'getwxinfo'); // qcloud.setLoginUrl(config.url + 'login'); }, globalData: { userInfo: null } }) 

这里注释掉了 qcloud.setLoginUrl 。打开定义为 qcloud 的 ./lib/index 文件,代码包括:

var constants = require('./constants');
var login = require('./login'); var Session = require('./session'); var request = require('./request'); var Tunnel = require('./tunnel'); var SocketTunnel = require('./socketTunnel'); var exports = module.exports = { login: login.login, setLoginUrl: login.setLoginUrl, LoginError: login.LoginError, clearSession: Session.clear, request: request.request, RequestError: request.RequestError, Tunnel: Tunnel, SocketTunnel: SocketTunnel, }; // 导出错误类型码 Object.keys(constants).forEach(function (key) { if (key.indexOf('ERR_') === 0) { exports[key] = constants[key]; } }); 

从上面的代码中,我们可以看到,除了 setLoginUrl ,qcloud 还有 login、clearSession、request、Tunnel、SocketTunnel、LoginError、RequestError 等方法。

login 函数需要在 app.js 中使用 setLoginUrl 设置与后台交互的 url 。设置 url 后,我们需要了解 login 是如何工作的,从而确认后台如何与 login 交互。

login.js 分析

打开 wxlite/lib/login.js 文件,我们可以看到模块输出三个方法:

module.exports = {
    LoginError: LoginError,
    login: login,
    setLoginUrl: setLoginUrl, }; 
setLoginUrl

我们先看 setLoginUrl ,这个函数的功能非常简单,设置后台登录 url :

var setLoginUrl = function (loginUrl) { defaultOptions.loginUrl = loginUrl; }; 

代码中,只是将 defaultOptions 的 loginUrl 设置为输入的 loginUrl 。这里 defaultOptions 是 login.js 定义的全局变量,它的初始化设置为:

var defaultOptions = {
    method: 'GET',
    success: noop, fail: noop, loginUrl: null, }; 

这里的 noop 为:

var noop = function noop() {}; 
LoginError

LoginError 是处理登录错误的,其代码为:

var LoginError = (function () { function LoginError(type, message) { Error.call(this, message); this.type = type; this.message = message; } LoginError.prototype = new Error(); LoginError.prototype.constructor = LoginError; return LoginError; })(); 
login
流程

login 方法用于实现登录功能,代码流程为:

 
login流程.jpg

这里,实际的动作为 获取 session,检查 session并进行相应操作。

获取 session 使用的 Session.get() 方法,打开 Session 对应的 session.js 文件,get() 方法的功能为从微信缓存中获取 'weapp_session_F2C224D4-2BCE-4C64-AF9F-A6D872000D1A' 对应的值。这个值是在第一运行 doLogin 时设置的。那么,我们接下来分析 doLogin 。

doLogin

doLogin 的代码为:

var doLogin = () => getWxLoginResult(function (wxLoginError, wxLoginResult) { if (wxLoginError) { options.fail(wxLoginError); return; } var userInfo = wxLoginResult.userInfo; // 构造请求头,包含 code、encryptedData 和 iv var code = wxLoginResult.code; var encryptedData = wxLoginResult.encryptedData; var iv = wxLoginResult.iv; var header = {}; header[constants.WX_HEADER_CODE] = code; header[constants.WX_HEADER_ENCRYPTED_DATA] = encryptedData; header[constants.WX_HEADER_IV] = iv; // 请求服务器登录地址,获得会话信息 wx.request({ url: options.loginUrl, header: header, method: options.method, data: options.data, success: function (result) { var data = result.data; // 成功地响应会话信息 if (data && data.code === 0 && data.data.skey) { var res = data.data if (res.userinfo) { Session.set(res.skey); options.success(res.iminfo); } else { var errorMessage = '登录失败(' + data.error + '):' + (data.message || '未知错误'); var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage); options.fail(noSessionError); } // 没有正确响应会话信息 } else { var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, JSON.stringify(data)); options.fail(noSessionError); } }, // 响应错误 fail: function (loginResponseError) { var error = new LoginError(constants.ERR_LOGIN_FAILED, '登录失败,可能是网络错误或者服务器发生异常'); options.fail(error); }, }); }); 

dologin 实行的是 getWxLoginResult 方法,这里定义的是方法成功或失败的回调方法。getWxLoginResult 的定义为:

var getWxLoginResult = function getLoginCode(callback) { wx.login({ success: function (loginResult) { wx.getUserInfo({ success: function (userResult) { console.log('[userResult]', userResult); callback(null, { code: loginResult.code, encryptedData: userResult.encryptedData, iv: userResult.iv, userInfo: userResult.userInfo, }); }, fail: function (userError) { console.log('[userError]', userError); var error = new LoginError(constants.ERR_WX_GET_USER_INFO, '获取微信用户信息失败,请检查网络状态'); error.detail = userError; callback(error, null); }, }); }, fail: function (loginError) { console.log('[loginError]', loginError); var error = new LoginError(constants.ERR_WX_LOGIN_FAILED, '微信登录失败,请检查网络状态'); error.detail = loginError; callback(error, null); }, }); }; 

结合这两个方法,可以分析 doLogin 的逻辑为:

 
doLogin流程.jpg

从这里我们可以看到,后台处理登录请求的视图将接收的 code、encryptedData 和 iv 放在请求头中,后台返回的响应至少需要返回 code、data 两个元素,如果成功执行,code 需要设为 0 ,data 中至少需要包含 skey 、userinfo 和 iminfo 三项内容。

用法

我们已经了解了 login 的基本原理,那么,我们应该怎样使用 login 呢?

与 login.js 位于同一文件夹的 request.js 提供设置 login 为 ture 的 Request 请求实现先登录后请求,我们看下这个方法是怎么使用 login.js 的。

request 中,如果定义了 login 为 true ,则requirLogin 为 true,请求将执行doRequestWithLogin()。

if (requireLogin) {
    doRequestWithLogin();
} else {
    doRequest();
}

doRequestWithLogin() 定义了登录后再请求的函数:

function doRequestWithLogin() { loginLib.login({ success: doRequest, fail: callFail }); } 

如果登录成功,将执行 doRequest() ,失败则执行 callFail()。

doRequest 执行时首先构造 authHeader 将从微信缓存中获取的 'weapp_session_F2C224D4-2BCE-4C64-AF9F-A6D872000D1A' 的值写到 X-WX-Skey 请求头中进行发送。

问题

整个流程中,如果登录过之后再次调用 login ,返回 Session.get() 中的 userinfo 。但是在首次登录成功时或者 request 设置login 为 true 的 request 成功时,Session.set() 设置的是 skey 的值,并没有 userInfo 的值。是否可以扩展 Session 中的方法来保存和读取用户信息。

转载于:https://www.cnblogs.com/wang-sai-sai/p/10729376.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值