You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测JavaScript应用中Sentry上报请求是否被拦截?

可靠追踪Sentry上报请求失败状态的方案

环境背景

我们的应用基于Angular/TypeScript开发,使用Sentry.io做错误上报。当应用抛出异常时,全局错误处理器会触发,弹出带文本框的自定义弹窗,用户提交消息后通过Sentry.captureMessage(…)将消息上报至Sentry。

现存问题

近期发现,当Sentry被广告拦截器等原因阻断无法访问时,我们收不到用户提交的消息。

需求目标

希望实现以下两种方案之一:

  • 提前检测Sentry可达性,若存在访问问题,直接展示联系支持的指引,不提供Sentry提交入口;
  • 保留Sentry提交入口,但在提交请求失败时,引导用户联系支持。

已尝试的非最优方案

我们检查过Sentry.captureMessage(…)的返回值,无论请求成功与否都会返回eventId,try/catch也捕获不到请求失败的异常;后续调用的Sentry.flush(…)返回Promise<boolean>,仅表示事件已被发送,不代表请求成功。

目前通过调用Sentry非公开内部API实现检测:

public sentryIsBlocked(): boolean | null {
    const client = Sentry.getCurrentHub().getClient();

    if (!client) return null;

    const numberOfNetworkSessionErrors = (client as any)['_outcomes']['network_error:session'];

    return !!numberOfNetworkSessionErrors && numberOfNetworkSessionErrors > 0;
}

该方法存在弊端:

  • 依赖非公开API,版本更新后可能失效;
  • 仅能检测历史请求问题,无法确认当前请求状态。

可靠解决方案

方案1:包装Sentry传输器实时捕获请求失败

利用Sentry公开的transport配置项,包装默认传输器的发送逻辑,直接捕获请求失败的异常:

import * as Sentry from '@sentry/angular';

Sentry.init({
  dsn: '你的DSN地址',
  transport: (options) => {
    // 创建默认的Fetch传输实例
    const defaultTransport = Sentry.makeFetchTransport(options);
    const originalSend = defaultTransport.send.bind(defaultTransport);

    // 重写send方法,添加错误捕获
    defaultTransport.send = async (event) => {
      try {
        const result = await originalSend(event);
        // 请求成功,可记录状态
        return result;
      } catch (error) {
        // 捕获到请求失败,这里触发你的引导逻辑
        console.error('Sentry上报请求失败:', error);
        // 比如设置全局状态,后续弹窗切换为联系支持入口
        window.sentryUnreachable = true;
        throw error; // 保留Sentry的重试逻辑(若不需要可移除)
      }
    };

    return defaultTransport;
  },
  // 其他初始化配置...
});

优势:

  • 基于Sentry公开API,版本兼容性有保障;
  • 实时捕获每一次上报请求的状态,准确反映当前Sentry可达性。

方案2:预检测Sentry可达性(提前判断)

如果需要在用户打开弹窗前就判断Sentry是否可用,可发起HEAD请求验证:

async function checkSentryReachable(): Promise<boolean> {
  const client = Sentry.getCurrentHub().getClient();
  const dsn = client?.getDsn();
  if (!dsn) return false;

  // 构造Sentry上报端点URL
  const endpoint = `${dsn.protocol}://${dsn.publicKey}@${dsn.host}/${dsn.projectId}/envelope/`;

  try {
    // 使用no-cors模式避免跨域限制,只要请求不抛出异常就说明未被拦截
    await fetch(endpoint, { method: 'HEAD', mode: 'no-cors' });
    return true;
  } catch (error) {
    // 请求被拦截或失败,标记Sentry不可用
    return false;
  }
}

// 弹窗打开前调用
if (await checkSentryReachable()) {
  // 展示Sentry提交入口
} else {
  // 展示联系支持指引
}

注意:no-cors模式下无法获取真实响应状态,但能判断请求是否被广告拦截器阻断。

方案3:结合Outcomes API(需后端配合)

Sentry的Outcomes API是公开的,可用来追踪事件投递状态。前端可以记录上报的eventId,由后端定时查询Outcomes API判断是否投递成功:

Sentry.init({
  dsn: '你的DSN地址',
  beforeSend: (event) => {
    // 记录当前上报的eventId
    window.lastReportedEventId = event.event_id;
    return event;
  },
});

后端通过Outcomes API查询该eventId的状态后,再通知前端处理用户引导逻辑。此方案适合需要持久化追踪上报结果的场景。


总结

优先选择方案1,它无需额外请求,基于Sentry公开API实现实时错误捕获,既满足实时判断需求,又避免了依赖非公开API的风险。

内容的提问来源于stack exchange,提问作者DerZyklop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:17:50