为什么要用云开发做错误日志:
我司没有测试,所以产品上线的话比较多不确定性
云开发业务并不稳定,且有限制,所以不建议直接用做整个小程序的后台开发。
做错误日志并不会影响小程序的流程
出 bug 后,难定位问题,尤其是线上错误
如果叫后端小伙伴给接口记录错误,总是不方便,还是自己动手丰衣足食
尝鲜
基于以上的原因,在小程序云开发刚出来没多久,我就开始着手在我的小程序上尝试构建一个错误日志:
一般用一门新技术的第一步,你需要先浏览一下小程序云开发的官方文档:https://developers.weixin.qq….
初始化环境然后你需要一个小程序,一个小程序开发工具:新建一个空白的小程序后,点击左上角的云开发按钮,初始化一个云开发的环境
我这里给它取名叫 error-storage。当然我是因为之后我的小程序也不太可能会用到云开发做后台,所以可以浪费一个环境命名。如果你是要用云开发做后台业务的话。那么还是按照微信推荐,一个做测试一个做正式,命名也尽量规范一点。然后它的环境限制也是我们目前不拿它当主要后端脚本的主要原因之一。ok,点击确定就创建了一个云开发后台了。
然后我们回到代码。
我们需要写后端脚本记录错误信息,那么根据云开发的文档,我们需要修改 project.config.json 给他配置一下小程序代码放在哪里,后端代码放在哪里。以下是我的配置:
我把小程序文件都放在了根目录下的 client 文件夹内,而云函数的文件则都放在了根目录的 server 文件夹的 cloudFunctions 里那么现在我们的目录结构是这样的。我们需要手动移动一下我们的小程序代码。
注意这里 project.config.json 是在根目录
现在先添加一个数据库集合,打开云开发控制台,点击数据库。添加一个叫 errors 的集合
编写接收错误的云函数
然后我们先开始写接收错误的云函数
用微信开发工具打开代码,然后点击目录树上面的 cloudFunctiions 目录,新建一个云函数,我们将它取名叫做 errorHandler
然后写上我们的代码逻辑
// 云函数入口文件
const cloud = require(‘wx-server-sdk’);
cloud.init();
const db = cloud.database();
const errorCllection = db.collection(‘errors’);
function addError(data) {
return errorCllection.add({
data: {
…data,
createTime: Date.now()
}
});
}
// 云函数入口函数
exports.main = async event => {
event.openid = event.userInfo.openId;
delete event.userInfo;
await addError(event);
return true;
};
这面这段代码很简单就是将小程序端传过来的错误写进数据库里面,错误信息是什么由小程序端决定,它仅仅只是将所有数据丢进数据库去而已保存字后再次右键 cloudFunctions 选择上传并部署。那么我们的服务端就基本搞定了。(好简单啊)
写小程序端的错误处理函数
首先,根据教程,我们要在 app.js 里面做云能力初始化在 app.js 的第一行添加代码
try {
wx.cloud.init({// 云开发初始化
env: ‘ 云环境 id’,
traceUser: true
});
} catch(err) {}
给它加上 catch 是因为防止出现一些错误导致 app.js 运行失败,那简直是灾难吧!这里的 env 是你的云环境 id,那么在哪里拿呢,在这里
然后我们在 client/utils 文件夹里面添加一个处理错误的模块吧名字就叫 error.js
const {config} = require(‘./config.js’);
global.onError = function (message, showModal = true) {
return function (error) {
wx.hideLoading();
if (showModal) {
wx.showModal({
title: ‘ 错误 ’,
content: error.msg || message,
// 这里的 error.msg 是因为与后端约定如果有什么错误,则带一个 msg 的描述
// 而 message 则是传入进来备用的错误信息
confirmText: ‘ 返回首页 ’,
cancelText: ‘ 继续操作 ’,
success: res => {
if (res.confirm) {
// 重新加载首页
wx.switchTab({
url: ‘/pages/index/index’
});
} else {
// 取消就不管了
}
}
});
}
// 上传到小程序云数据库
try {
let userInfo = getApp().globalData.userInfo,
systemInfo = wx.getSystemInfoSync(),
page = getCurrentPages();
// 只有不在开发工具上触发的才上报
if (systemInfo.platform !== ‘devtools’) {
wx.getNetworkType({
success: res => {
wx.cloud.callFunction({
name: ‘errorHandler’,
data: {
username: userInfo.nickName,
uid: userInfo.id,
clientType: systemInfo.model,
systemInfo: JSON.stringify(systemInfo),
pageRoute: page[page.length – 1].route,
message: error.msg || message,
version: config.version,
networkType: res.networkType,
errorTime: new Date(),
error: typeof error === ‘object’ ? JSON.stringify(error) : String(error)
}
});
}
});
}
} catch(err) {}
console.error(‘ 程序发生错误:\n’, ‘ 时间:\n’, new Date(), ‘\n 错误信息:\n’, message, ‘\nvvvvvvvvvvvvvv\n’, error);
};
};
如上,除了错误信息之外,还储存了系统信息,网络类型,最顶部的页面路由,错误时间,用户信息,版本号等 (这里我加了个 config.js 用以储存版本号,版本描述等信息)
用 try catch 包起来也是为了防止触发错误导致死循环
并且为了方便使用,我将其直接挂载到 global。不喜欢全局变量的童鞋可以选择 export 出去再引用
并且在触发错误的时候弹出一个提示框提示错误了。
错误处理函数的使用那么接下来就是对这个方法的使用了,首先我们要监听 app.js 的 onError 方法,小程序页面逻辑出现错误都会到这个方法内
request(‘./utils/error.js’); // 别忘了引入 error.js
App({
onError: global.onError(‘ 程序发生错误 ’) // 这里返回接受错误的函数的闭包,并且传入的 ’ 程序发生错误 ’ 则是未知错误发生时的提示语
});
而其他的应用基本是应用到在 promise 的错误监听上,由于 promise 中的错误不会被 app.js 的 onError 接收到,所以我们需要在每个 promise 的 catch 中使用 global.onError 这也是我为什么将 onError 挂载 global 的原因,因为基本每个页面都会用到,所以每个页面去引用的话很麻烦
例子:demo.js
Page({
onLoad() {
wx.showLoading();
this.requestList()
.then(res => {
// 做一些事情
})
.catch(global.onError(‘ 获取列表数据失败!’));
},
requestList() {
return new Promise((resolve, reject) => {
wx.request({
url: ‘https://mock.com/aaa’,
success: resolve,
fail: reject
});
});
}
});
那么,到现在,基本上已经完成了,愉快的开发,再也不担心出现完全没有头绪的错误啦最后贴一张我收集到的错误吧。但是有些字段我做了调整
最后还是要吐槽一下微信本身它自己的 bug 有点多。实在是很无奈的