☀️ 前言
微信小程序的项目接入监控,由于引入了第三方组件库,导致无法监控到组件库的请求,但部分组件库的 wx.request
请求又需要被监控,以便于bug定位(方便把锅甩了😏),如何解决?而且令头秃更近一步的是 request
的方法是只读属性不能直接赋值。
尝试直接赋值,啪啪打脸秒来了。
这时候想起了先做个好宝宝,乖乖查一下 request
属性的描述信息吧。
由此可以看到request
是只读属性,因此直接赋值是不被允许。那是不是意味着对于目前的场景就完全解决不了呢?需求不停代码不止,微信为了给我们程序猿们留下可扩展的空间 request
是configurable: true
,也就给覆写留了一个小小的口子,啥也不说了开干吧。
🤔 使用的奇巧淫技
当对象的属性的 configurable
键值为 true
时,是可以对属性的描述进行再次 config
的。而 ES5
提供了 Object.defineProperty
和 Object.defineProperties
这两个方法对属性进行设置。这两个方法的作用都是在一个对象上定义新的属性或修改现有属性,并返回该对象。区别就是批量操作配置和单一配置。
关于 Object.defineProperty
和 Object.defineProperties
这两个方法详细介绍可以参看 MDN的介绍。
🔥 覆写开干
既然奇巧淫技有了那咱干就完了,我以为的💐就要来了,完美的写出了第一版代码。
function hookRequest (options: WechatMiniprogram.RequestOption) {
const hookOptions = {
success: function (res: any) {
options.success?.(res);
console.log(res, options.url, 'request success');
},
fail: function (res: any) {
options.fail?.(res);
console.log(res, 'request fail');
},
};
const requestOptions = Object.assign(options, hookOptions);
return wx.request(requestOptions);
};
Object.defineProperty(wx, 'request', {
value: hookRequest,
});
理想是丰满的,现实是骨感的,我被现实响亮了打了几个大嘴巴子,你以为的并不是你以为的。
这鲜亮的红色总是这么醒目且刺眼,这兜底的页面就是这么直接的出现了,现实一个绝情脚让我明白了写代码不能想象,踏实搞吧。
const originRequest = wx.request;
function hookRequest (options: WechatMiniprogram.RequestOption) {
const originOptions = options;
const { success, fail } = originOptions;
const hookOptions = {
success: function (res: any) {
success?.(res);
console.log(res, options.url, 'request success');
},
fail: function (res: any) {
fail?.(res);
console.log(res, 'request fail');
},
};
const requestOptions = Object.assign({}, originOptions, hookOptions);
return originRequest(requestOptions);
};
Object.defineProperty(wx, 'request', {
value: hookRequest,
});
果然剔除想象的代码是可以正常运行的。
❓ 解决拦路虎
代码跑起来了,现在我们来分析一下刚刚我们想象中的代码为什么跪了。这里面一共出现了两个问题:
RangeError: Maximum call stack size exceeded
的报错,理论上代码层面没有递归调用不应该有堆栈溢出的问题,但现在有报错,说明哪里出现了递归。- 出现了死循环,
success
与fail
函数被不停的调用了,说明哪里出现了死循环。
针对第一个问题我们看一下代码,在执行了 Object.defineProperty
时,request
方法实际已经是 hookRequest
了,但是在 hookRequest
执行 wx.request
实际执行的是自身即是 hookRequest
这也就形成递归了也就造成了溢出。因此这里需要在 defineProperty
前暂存一下 wx.request
然后再进行调用。
const originRequest = wx.request;
function hookRequest (options: WechatMiniprogram.RequestOption) {
return originRequest(options);
}
Object.defineProperty(wx, 'request', {
value: hookRequest,
});
由此就可以解决 RangeError: Maximum call stack size exceeded
的问题。
针对第二个问题我们看一下代码,代码中执行 const requestOptions = Object.assign(options, hookOptions);
这时实际我们已经修改了 options
的 success
与 fail
函数值,因此在 success
与 fail
函数中调用 options.success?.(res);
和 options.fail?.(res);
时实际是调用修改后的 success
与 fail
方法,这也造成了死循环的出现。因此需要 success
与 fail
调用原来的 options
上的方法即可,最简单的方式就是不要修改 options
的内容,对于 requestOptions
可以使用 const requestOptions = Object.assign({}, options, hookOptions);
。
const originRequest = wx.request;
function hookRequest (options: WechatMiniprogram.RequestOption) {
const hookOptions = {
success: (res: any) => {
options.cuccess?(res);
},
fail: (res: any) => {
options.fail?(res);
},
};
const requestOptions = Object.assign({}, options, hookOptions);
return originRequest(requestOptions);
}
Object.defineProperty(wx, 'request', {
value: hookRequest,
});
由此也就解决掉死循环的问题了,对于 Object.assign
详细介绍可以看一下 MDN
。
👋 写在最后
- 虽然这是一个特定场景遇到的问题,但是解决问题的过程我也变强了,这里记录一下分享给大家。
- 如果觉得这篇文章还不错的话不妨🍉🍉关注+点赞+收藏+评论+转发🍉🍉支持一下码字的不易。