【问题标题】:TypeError: Illegal Invocation类型错误:非法调用
【发布时间】:2021-07-17 08:39:49
【问题描述】:

我们正在运行一个 Create React App (CRA) 网络应用,我们在其中添加了 Google Analytics v4。我们使用ga-4-react npm 包启动分析。在index.js中手动初始化

const ga4react = new GA4React(process.env.REACT_APP_GOOGLE_ANALYTICS_ID);

ga4react.initialize().then((ga4) => {
    ga4.pageview(window.location.path);
}, (err) => {
    Sentry.captureException(err);
});

我们从gtag/js 文件中收到数百个错误,这些错误发送到我们的 Sentry 错误监控平台。这个错误对我们来说并没有什么太大的意义,我们花了两天时间试图找出是否有人遇到过这样的问题,但到目前为止我们还是一无所获。好像也不会影响用户体验,但是监控起来比较烦人。

错误会这样报告给 Sentry。

TypeError zq(gtag/js)
Illegal invocation

gtag/js in zq at line 477:453
{snip} ))}}},zq=function(a,b,c){var d=a+"?"+b;c?$c.sendBeacon&&$c.sendBeacon(d,c):pd(d)};var Eq=window,Fq=document,Gq=function(a){var b=Eq._gaUserP {snip}

我们还从 ga-4-react(上面代码 sn-p 中的 catch-block)收到了同样多的错误。我们还尝试使用带有 react-helmet 的分析 sn-p,但结果相同。

此错误似乎是由许多平台(Android、Windows 10、OS X)上的许多浏览器(Chrome、Opera、Safari、移动浏览器)产生的,因此我们无法真正确定任何特定的路线、平台、浏览器这在这些用户中很常见。

我还尝试使用 AdBlock 复制此功能,阻止跟踪器,使用 Do Not Track,但没有。

【问题讨论】:

  • Atm 我们正在尝试使用环境变量将脚本嵌入到静态 index.html 文件中,看看这是否解决了我们的问题。
  • 这不起作用。我们仍然收到来自 gtag/js 的 TypeError
  • 从您发布的错误消息中,我们已经可以精确定位到$c.sendBeacon 调用。当您使用错误的上下文对象调用本机 API 时,会发生“非法调用”。 $c 应该是内置的navigator 接口,navigator.sendBeacon 必须与navigator 作为其上下文对象一起调用。否则你会得到这个错误。如果我的理论是正确的,你可以用这一行重现:navigator.sendBeacon = navigator.sendBeacon.bind({}) 在初始化 GA 之前运行它。
  • 所以它可能是一些用户端扩展惹恼了你。但是你提到这也发生在移动浏览器上,这很奇怪。 AFAIK,“非法调用”是特定于 chrome 的错误消息,您是否从其他平台收到其他消息(相同的错误)?如果你没有看到其他消息,那么,另一种可能是同一个扩展也篡改了user-agent字段或种类,从而伪装成其他平台,但实际上它只是chrome。
  • @Rcls 如果排除来自外部脚本的错误,因为我们无法控制这一点。,那么这个问题的预期是什么?我的意思是,如果外部脚本被sentry 标记,您是否希望得到解决外部包的答案?

标签: javascript reactjs google-analytics


【解决方案1】:

在我们的网站上遇到了同样的问题。此问题似乎源于 navigator.sendBeacon 被断章取义地调用,类似于来自 hackape 的评论。

就上下文而言,本文提供了一些关于 sendBeacon 及其作用的非常好的信息,包括对您所看到的错误的描述。

https://xgwang.me/posts/you-may-not-know-beacon/

在我们的例子中,我们只看到了类型错误:非法调用,但没有看到他们提到的基于不同浏览器的其他错误消息变体。最后我们暂时忽略了它。

【讨论】:

  • 我在 Sentry 中遇到了同样的问题。只是想知道自这篇文章以来您是否学到了任何新东西,或者您是否仍然在 Sentry 中忽略了这个问题。
  • 很遗憾,没有。我们暂时忽略它,直到我们看到足够多的实例表明大部分用户受到影响。
  • 我在 Sentry 无法忽略时遇到问题,因为它不能很好地合并它们:/
【解决方案2】:

您可以使用此代码示例

import React from "react";
import ReactDOM from "react-dom";
import GA4React, { useGA4React } from "ga-4-react";

const ga4react = new GA4React("G-1JXXXXX");

function MyApp() {
  const ga = useGA4React();
  console.log(ga);

  return <div className="App">hi!</div>;
}

(async () => {
  await ga4react.initialize();

  ReactDOM.render(
    <React.StrictMode>
      <MyApp />
    </React.StrictMode>,
    document.getElementById("root")
  );
})();

【讨论】:

  • 我们在 hooks (16.13.1) 之前运行 React,所以这不是一个真正的选择。我还要争辩说,如果您查看源代码(就像我所做的那样),挂钩只会启动与手动初始化相同的功能。它只是在一个功能组件内并通过一个钩子来完成,这很有帮助,但使用相同的功能。
【解决方案3】:

使用react-ga npm 包通过以下代码实现 Google Analytics

创建帮助文件,这将帮助您了解 DRY 概念

import ReactGA from 'react-ga';

/**
 * Initialize Google Analytics
 */
export const initializeGA = () => {
  ReactGA.initialize(process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_KEY, {
    debug: true
  });
};

/**
 *  Push Page Tracking on Google Analytics
 */
export const pageView = () => {
  ReactGA.pageview(window.location.pathname + window.location.search);
};

然后在你的根组件上初始化 Google Analytics

import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { initializeGA, pageView } from '../helpers/analytics';

export default function MyApp() {
  const location = useLocation();

  useEffect(() => {
    initializeGA();
  }, []);

  useEffect(() => {
    pageView();
  }, [location.pathname]);

  return (
    <div>
      <p>Your root component text</p>
    </div>
  );
}

如果您使用的是旧的 React 版本,则可以使用 class component 和生命周期挂钩 componentDidMountcomponentDidUpdate/componentWillRecieveProps 根据您的 React 版本来实现。相同的示例是。

import { browserHistory } from 'react-router';

class App extends React.Component {
  componentDidMount() {
    this.unlisten = browserHistory.listen((location) => {
      console.log('route changes');
    });
  }
  componentWillUnmount() {
    this.unlisten();
  }
  render() {
    return (
      <div>
      </div>
    );
  }
}

【讨论】:

    【解决方案4】:

    您正在使用ga4.pageview(window.location.path);,但path 不是window.location 的属性

    尝试改用pathname

    ga4.pageview(window.location.pathname);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-29
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多