线上Bug炸了,用户骂你你却不知道?前端监控教你“远程开天眼”

前言

想象你开了一家无人超市。你坐在办公室,突然收到投诉:货架倒了、扫码枪坏了、冷柜不制冷了。你跑过去一看,一切正常。然后你走了,问题又出现。你需要一套远程监控系统:实时看到每个货架的状态、每笔交易的成功率、每个摄像头的画面。这就是前端监控的活。

前端监控就是给网站装"黑匣子":记录错误、性能、用户行为,然后上报到服务器,让你能在后台看到一切。今天我们就来搭一套简易但够用的前端监控系统。

一、监控什么?四个核心维度

  • 错误监控:JS报错、Promise拒绝、资源加载失败、API接口报错。
  • 性能监控:页面加载时间、首次渲染、DOM ready、接口响应时间。
  • 用户行为:点击、路由跳转、页面停留时长、用户操作路径。
  • 业务数据:比如"支付成功率"、"注册完成率"。

二、错误监控:抓尽所有"漏网之鱼"

1. JS运行时错误

window.onerror捕获同步错误和部分异步错误。

js 复制代码
window.onerror = function(message, source, lineno, colno, error) {
  const report = {
    type: 'jsError',
    message,
    stack: error?.stack,
    file: source,
    line: lineno,
    col: colno,
    userAgent: navigator.userAgent,
    url: location.href
  };
  sendReport(report); // 上报到服务器
  return true; // 阻止默认控制台输出
};

2. Promise 未捕获的拒绝

unhandledrejection捕获未处理的Promise reject。

js 复制代码
window.addEventListener('unhandledrejection', (event) => {
  const report = {
    type: 'promiseError',
    reason: event.reason,
    stack: event.reason?.stack
  };
  sendReport(report);
});

3. 资源加载失败(图片、script、link)

js 复制代码
window.addEventListener('error', (event) => {
  if (event.target !== window) {
    const report = {
      type: 'resourceError',
      tagName: event.target.tagName,
      src: event.target.src || event.target.href
    };
    sendReport(report);
  }
}, true); // 捕获阶段

4. Vue/React 组件错误

Vue:Vue.config.errorHandler

React:componentDidCatchErrorBoundary

js 复制代码
// Vue
Vue.config.errorHandler = (err, vm, info) => {
  sendReport({ type: 'vueError', err, info });
};

// React
class ErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    sendReport({ type: 'reactError', error, errorInfo });
  }
  render() { return this.props.children; }
}

5. 接口请求错误(axios/fetch)

拦截axios响应或重写fetch。

js 复制代码
// axios 拦截器
axios.interceptors.response.use(
  response => response,
  error => {
    sendReport({
      type: 'apiError',
      url: error.config.url,
      status: error.response?.status,
      message: error.message
    });
    return Promise.reject(error);
  }
);

三、性能监控:谁拖慢了页面?

js 复制代码
window.addEventListener('load', () => {
  const timing = performance.timing;
  const report = {
    type: 'performance',
    dns: timing.domainLookupEnd - timing.domainLookupStart,
    tcp: timing.connectEnd - timing.connectStart,
    ttfb: timing.responseStart - timing.requestStart,
    domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
    load: timing.loadEventEnd - timing.navigationStart
  };
  sendReport(report);
});

2. 首屏时间(自定义)

可以用MutationObserver检测页面关键元素出现的时间。

3. 使用 Web Vitals(Core Web Vitals)

Google推荐的三个指标:LCP(最大内容绘制)、FID(首次输入延迟)、CLS(累积布局偏移)。可以用web-vitals库。

js 复制代码
import {getLCP, getFID, getCLS} from 'web-vitals';
getLCP(metric => sendReport({type: 'webVital', name: 'LCP', value: metric.value}));
// 同理 FID, CLS

四、用户行为监控:他到底点了哪里?

记录关键操作:页面访问、点击、路由变化、表单提交。

1. 路由变化

SPA里监听popstatepushState(需要重写)。

js 复制代码
const originalPushState = history.pushState;
history.pushState = function(...args) {
  originalPushState.apply(this, args);
  sendReport({ type: 'routeChange', url: location.href, method: 'pushState' });
};
window.addEventListener('popstate', () => {
  sendReport({ type: 'routeChange', url: location.href, method: 'popstate' });
});

2. 点击事件

全局监听click,上报目标元素的关键信息(避免上报敏感信息)。

js 复制代码
document.addEventListener('click', (e) => {
  const target = e.target;
  const report = {
    type: 'click',
    tag: target.tagName,
    text: target.innerText?.slice(0, 50),
    className: target.className,
    id: target.id
  };
  sendReport(report);
});

注意防抖和采样(比如只上报10%的点击),避免上报量过大。

五、上报方式:怎么把数据传回来?

  • 使用navigator.sendBeacon:页面关闭时也能保证发送,不阻塞跳转。
  • 图片打点(GET)new Image().src = '/log?data=...',简单,跨域友好。
  • POST请求 :数据量大时用fetch,注意跨域和失败重试。
js 复制代码
function sendReport(data) {
  const url = 'https://your-monitor-server.com/report';
  if (navigator.sendBeacon) {
    navigator.sendBeacon(url, JSON.stringify(data));
  } else {
    fetch(url, {
      method: 'POST',
      body: JSON.stringify(data),
      keepalive: true
    }).catch(e => console.warn('上报失败', e));
  }
}

六、采样与去重:别把服务器打满

  • 采样:只上报一部分用户(比如10%),用随机数或用户ID哈希。
  • 去重:同一错误连续触发多次,可以合并上报(比如5秒内只报一次)。
js 复制代码
const errorCache = new Map();
function dedupeReport(errorKey, data, delay = 5000) {
  if (errorCache.has(errorKey)) return;
  errorCache.set(errorKey, true);
  sendReport(data);
  setTimeout(() => errorCache.delete(errorKey), delay);
}

七、推荐工具:不用自己造轮子

  • Sentry:最流行的错误监控,支持全框架,提供SourceMap上传、错误聚合、报警。
  • Fundebug:国内,支持微信小程序。
  • 阿里ARMS腾讯RUM:企业级。
  • 自建:可以用Elasticsearch + Kibana,或直接买第三方服务。

八、实战:最小化监控SDK

js 复制代码
class Monitor {
  constructor(serverUrl) {
    this.url = serverUrl;
    this.init();
  }
  init() {
    window.onerror = (msg, file, line, col, err) => this.send('js', { msg, file, line, col, stack: err?.stack });
    window.addEventListener('unhandledrejection', e => this.send('promise', { reason: e.reason }));
    // 其他监听...
  }
  send(type, data) {
    const payload = { type, data, time: Date.now(), ua: navigator.userAgent, url: location.href };
    navigator.sendBeacon(this.url, JSON.stringify(payload));
  }
}
new Monitor('https://your-server.com/api/log');

九、总结:监控是你的"远程遥控器"

  • 监控错误、性能、行为、业务数据。
  • onerrorunhandledrejection、资源错误捕获。
  • 上报用sendBeacon,注意采样去重。
  • 生产环境推荐用Sentry等成熟方案。

有了监控,用户还没投诉,你已经知道Bug在哪,连夜修复。第二天用户起床,Bug已消失,还以为自己卡了。这就是前端监控的魔力。


如果你觉得今天的"天眼"够犀利,点个赞让更多人看到。明天我们将聊聊微前端------巨石应用拆解术,多个团队并行开发的终极方案。我们明天见!

相关推荐
网络点点滴1 小时前
创建一个简单的web服务器
运维·服务器·前端
kisloy2 小时前
【反爬虫】极验4 W参数逆向分析
java·javascript·爬虫
XPoet2 小时前
AI 编程工程化:MCP——给你的 AI 员工打通外部能力
前端·后端·ai编程
夏雪之晶莹2 小时前
JSON语法结构
javascript
笨笨狗吞噬者2 小时前
小程序包体积分析利器 -- vite-plugin-component-insight
前端·微信小程序·uni-app
吴声子夜歌2 小时前
Vue3——v-for指令
前端·javascript·vue
你的牧游哥2 小时前
Cursor IDE Rules / Skills / Subagents 前端项目配置全指南
前端·ide
音仔小瓜皮2 小时前
【Vue】什么时候用Ref?什么时候用shallowRef?
前端·javascript·vue.js
码喽7号2 小时前
vue学习五:前端路由VueRouter
前端·vue.js·学习