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

如何在动态加载脚本时检测403等错误状态码?

如何捕获动态加载脚本的HTTP错误状态码?

你碰到的这个问题我之前也遇到过——try/catch完全没反应,onerror又拿不到具体的状态码,确实挺头疼的。核心原因是:把<script>插入DOM的同步操作本身不会抛出网络错误,真正的HTTP错误是在后续异步的请求过程中发生的,所以同步的try/catch根本抓不到它,而原生的script.onerror事件确实不会直接返回状态码信息。

下面给你两个实用的解决方案,你可以根据场景选择:


方案1:先用Fetch API做预检请求(推荐)

这个思路是先通过fetch请求脚本的URL,直接拿到HTTP响应的状态码,确认请求没问题后再创建脚本元素插入DOM。这样既能精准捕获403、404这类状态码,还能提前给用户反馈。

优点是兼容性好,状态码获取稳定;唯一的小缺点是会多一次HTTP请求,但用HEAD方法的话只会请求响应头,不会下载脚本内容,开销很小,而且浏览器缓存会帮你处理重复请求的问题。

改造后的代码示例:

private _scripts: { [key: string]: Subject<Event> } = {};

load(url: string): Observable<Event> {
  if (this._scripts[url]) {
    return this._scripts[url].asObservable();
  }

  const subject = new ReplaySubject<Event>(1);
  this._scripts[url] = subject;

  // 用HEAD请求预检,获取状态码(也可以用GET,HEAD更轻量)
  fetch(url, { method: 'HEAD' })
    .then(response => {
      if (!response.ok) {
        // 这里可以根据状态码自定义错误信息
        const error = new Error(`脚本加载失败:${response.status} ${response.statusText}`);
        // 给错误对象附加状态码属性,方便上层处理
        (error as any).statusCode = response.status;
        subject.error(error);
        return;
      }

      // 预检通过,创建脚本元素加载实际内容
      const script = this.document.createElement("script");
      script.src = url;
      script.onload = (event: Event) => {
        subject.next(event);
        subject.complete();
      };
      script.onerror = (error: string | Event) => {
        subject.error(error);
      };
      this.document.head.appendChild(script);
    })
    .catch(fetchError => {
      // 捕获网络层面的错误,比如断网、跨域问题
      subject.error(fetchError);
    });

  return subject.asObservable();
}

方案2:利用Performance API获取请求状态

如果不想多一次请求,可以在onerror触发后,通过浏览器的Performance API去查找对应请求的状态记录。不过这个方法有个限制:跨域场景下,如果服务器没有配置合适的CORS头,responseStatus会返回0,拿不到具体状态码。

代码示例:

private _scripts: { [key: string]: Subject<Event> } = {};

load(url: string): Observable<Event> {
  if (this._scripts[url]) {
    return this._scripts[url].asObservable();
  }

  const subject = new ReplaySubject<Event>(1);
  this._scripts[url] = subject;

  const script = this.document.createElement("script");
  script.src = url;
  
  script.onload = (event: Event) => {
    subject.next(event);
    subject.complete();
  };
  
  script.onerror = () => {
    // 查找对应URL的性能记录
    const entries = performance.getEntriesByName(url) as PerformanceResourceTiming[];
    if (entries.length > 0) {
      const lastEntry = entries[entries.length - 1];
      const statusCode = lastEntry.responseStatus;
      let errorMsg = '脚本加载失败';
      // 根据状态码补充具体提示
      if (statusCode) {
        errorMsg += `:${statusCode}${statusCode === 403 ? '(未授权)' : ''}`;
      }
      subject.error(new Error(errorMsg));
    } else {
      subject.error(new Error('脚本加载失败,无法获取错误详情'));
    }
  };

  this.document.head.appendChild(script);
  return subject.asObservable();
}

最后补充两句:

  • 优先选方案1,状态码获取更可靠,尤其是跨域场景;
  • 如果用方案2,记得测试跨域环境下的表现,确保服务器配置了Timing-Allow-Origin头,否则拿不到状态码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 14:12:51