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

重写EventSource时触发'Uncaught TypeError: Illegal invocation'错误求助

问题详情

在线演示地址

https://www.w3schools.com/html/tryit.asp?filename=tryhtml5_sse

问题描述

我尝试重写EventSource,实现每当onmessage触发时执行console.log输出日志。

代码示例

<!DOCTYPE html>
<html>
<body>

<h1>Getting server updates</h1>
<div id="result"></div>

<script>
if (typeof EventSource !== "undefined") {

  const original = EventSource;

  // part of chrome extension
  window.EventSource = function EventSource(url) {
    const ori = new original(url);

    Object.getPrototypeOf(ori).onmessage = function (event) {
      console.log(event); // log on every message
      ori.onmessage(event);
    };

    return ori;
  };
  
  // actual source code
  var source = new EventSource("demo_sse.php");
  source.onmessage = function (event) {
    document.getElementById("result").innerHTML += event.data + "<br>";
  };
} else {
  document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>

</body>
</html>

报错信息

VM461:10 Uncaught TypeError: 非法调用
at new EventSource (:10:42)
at :21:16
at submitTryit (tryit.asp?filename=tryhtml5_sse:853:17)
at HTMLButtonElement.onclick (tryit.asp?filename=tryhtml5_sse:755:133)
EventSource @ VM461:10
(anonymous) @ VM461:21
submitTryit @ tryit.asp?filename=tryhtml5_sse:853
onclick @ tryit.asp?filename=tryhtml5_sse:755
uic.js?v=1.0.5:1 Uncaught ReferenceError: adngin 未定义
at uic_r_p (uic.js?v=1.0.5:1:54492)
at HTMLButtonElement.onclick (tryit.asp?filename=tryhtml5_sse:755:148)
uic_r_p @ uic.js?v=1.0.5:1
onclick @ tryit.asp?filename=tryhtml5_sse:755

解决方案

你的代码存在两个核心问题:

  1. 非法调用错误:自定义的EventSource构造函数未正确继承原生构造函数的原型链,导致浏览器无法识别其为合法的EventSource实例。
  2. 日志逻辑失效:直接修改EventSource.prototype.onmessage会被后续设置的实例onmessage覆盖,且存在无限递归风险。

修复后的代码如下:

if (typeof EventSource !== "undefined") {
  const original = EventSource;

  // 自定义EventSource构造函数,保留原生功能并添加日志
  window.EventSource = function(...args) {
    const instance = new original(...args);
    
    // 添加message事件监听器实现日志,不影响原有onmessage逻辑
    instance.addEventListener('message', (event) => {
      console.log('SSE消息:', event);
    });

    return instance;
  };

  // 保留原生原型链,避免类型检查失败
  Object.setPrototypeOf(window.EventSource, Object.getPrototypeOf(original));
  window.EventSource.prototype = original.prototype;
  
  // 原有业务代码不变
  var source = new EventSource("demo_sse.php");
  source.onmessage = function (event) {
    document.getElementById("result").innerHTML += event.data + "<br>";
  };
} else {
  document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持服务器推送事件...";
}

修复说明:

  • 使用addEventListener监听message事件,既实现日志输出,又不会与业务代码的onmessage冲突,两者都会执行。
  • 通过Object.setPrototypeOf和原型赋值,确保自定义构造函数与原生EventSource保持一致的原型链,解决非法调用问题。
  • 使用扩展运算符...args接收所有构造参数,兼容原生EventSource的完整参数列表(如可选的options参数)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:40:56