為什么要用云開發做錯誤日志:
我司沒有測試,所以產品上線的話比較多不確定性
云開發業務并不穩定,且有限制,所以不建議直接用做整個小程序的后臺開發。
做錯誤日志并不會影響小程序的流程
出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有點多。實在是很無奈的