【问题标题】:Angular 2. Error: Loading chunk failedAngular 2. 错误:加载块失败
【发布时间】:2017-05-17 20:15:15
【问题描述】:

使用带有延迟加载模块的 Angular 2,我可以从服务器接收(例如)401 HTTP 代码

bootstrap 0b40fee…:101 GET http://localhost:8082/2.chunk.js

Error: Loading chunk 2 failed.
at HTMLScriptElement.onScriptComplete (bootstrap 0b40fee…:91)
at HTMLScriptElement.wrapFn (zone.js:1032)
at ZoneDelegate.invokeTask (zone.js:414)
at Object.onInvokeTask (core.es5.js:4119)
at ZoneDelegate.invokeTask (zone.js:413)
at Zone.runTask (zone.js:181)
at HTMLScriptElement.ZoneTask.invoke (zone.js:476)

如何处理这个错误?

【问题讨论】:

  • 您如何为您的应用程序提供服务?使用 ng serve 或 stg 其他?这种问题可能与路径错误有关,您能否提供更多详细信息?
  • 路径没问题。问题是如何处理加载块(webpack)错误。原因可以是任何 HTTP 错误代码
  • 这里有一个类似的问题,更多地关注网络连接丢失而不是 401 类型错误。还有一个 NavigationError 事件,您可能可以加入其中,并至少获取 URL。

标签: javascript angular typescript


【解决方案1】:

详情请查看my answer

  • 绕过此块失败错误的解决方法 => 如果使用 global error handler 发生块失败错误,则以编程方式强制应用重新加载。

import { ErrorHandler } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  handleError(error: any): void {
   const chunkFailedMessage = /Loading chunk [\d]+ failed/;

    if (chunkFailedMessage.test(err.message)) {
      window.location.reload();
    }
  }
}
  • 在我们的根模块中提供它以更改我们应用程序中的默认行为,因此我们使用自定义的 GlobalErrorHandler 类来代替默认的 ErrorHandler 类。

@NgModule({   
  providers: [{provide: ErrorHandler, useClass: GlobalErrorHandler}]
})

【讨论】:

  • 它发生在导航期间。是否可以重新加载到目标页面?
  • 如果您已经在浏览器中打开了应用程序,并且当您尝试导航路由加载块失败时进行了新的构建部署,则会出现问题,因为浏览器正在使用已经缓存的块而不是新部署的块。
  • 新构建部署后硬刷新(control + shift + R)页面以加载新块
  • @WalterLuszczyk,您可以查看我的答案以获取应该自动处理重定向到用户所需页面的解决方案。
【解决方案2】:

我遇到了同样的问题,所以我进行了调查。我找到了解决方案。当我重新部署到另一台服务器并且该块具有 [hash] 时,这发生在我身上。

您可以像这样在 catch all 中捕获错误:

ngOnInit() {
    if (!this.previousRouterErrorHandler) {
        this.previousRouterErrorHandler = this.router.errorHandler;
        let that = this;
        this.router.errorHandler = function (err: any) {
            // Handle here. err.message == "Loading chunk chunk-name failed."

            return that.previousRouterErrorHandler.apply(that.previousRouterErrorHandler, arguments);
        };
    }
}

或直接在导航的链接处

click() {
    this.router.navigate(['/lazy-route'])
        .catch(err => {
            // Handle here
        });
}

【讨论】:

  • 谢谢!使用你的想法,我只是简单地为 this.router.errorHandler 设置了一个函数,这样我就可以捕获这些块错误。
  • 但是您如何处理这种情况?我的意思是,它本身并不能解决问题,它只是帮助你抓住它。
  • 这不是最好的,但我抛出一个弹出窗口说他们必须刷新一条消息“我们有一个更新,完成你正在做的事情并刷新页面。”不幸的是,Angular 不支持开箱即用的更好的东西。
【解决方案3】:

这是我的解决方案。我将此服务作为单例注入到我的应用程序/核心模块中。

它等待来自路由器的 NavigationError 实例,检查它们是否是 ChunkLoadError 的,然后重定向到用户想要去的地方。

// Angular
import { Injectable, OnDestroy } from '@angular/core';
import { Router, NavigationError } from '@angular/router';
// Rxjs
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

@Injectable()
export class ChunkErrorHandler implements OnDestroy {
  private subscription: Subscription;

  constructor(router: Router) {
    this.subscription = router.events
      .pipe(filter(event => event instanceof NavigationError))
      .subscribe(event => {
        this.handleRouterErrors(event as NavigationError);
      });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  private handleRouterErrors(event: NavigationError) {
    if (event.error.name === 'ChunkLoadError') {
      window.location.href = `${window.location.origin}${event.url}`;
    }
  }
}

【讨论】:

    【解决方案4】:

    在部署新代码时会发生这种情况。保存文件和哈希的manifest.js 在不刷新的情况下不会更新,当它加载一个块时,它显然使用 manifest.js 中的旧哈希。

    因此,在捕获错误时,我们可以使用给定的 url 强制重新加载:-

    click() {
          this.router.navigate(['/lazy-route'])
               .catch(err => {
                  // Handle here
                  // reload with given route
                  // window.location.pathname('/lazy-route');
    
                  // OR
                  // reset existing route(containing query params) with given route and force reload
                   window.history.pushState({}, document.title, '/lazy-route' );
                   window.location.reload();
               });
     }
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
    • 您能否详细说明此解决方案。
    【解决方案5】:

    任何环境或路由相关问题都可能引发与块相关的错误,这使得它们难以揭穿。

    在我的情况下,我的 PWA 中移动的数据量太多,无法由 angular 路由器处理。它淹没了 js 块 getter 的标头,因此引发了 bad_request 错误。

    我建议你检查那些网络调用(像 http://localhost:xxxx/158.js 这样的 chunks.js 的获取器)是否有任何异常的标头,并在你当前的开发环境中重构粗略的东西,因为这是一个真正的黑洞时间来调查源自己的错误。

    希望对你有帮助

    【讨论】:

      【解决方案6】:

      查看 Catch Storage,我想 service worker 会在 catch storage 中保存一些东西

      【讨论】:

      • 嗨@joshua - 您能否提供资源文档的链接?
      【解决方案7】:

      就我而言,我将文件放在 S3 存储桶中。我一直收到此错误,因为它一起调用了错误的文件名并返回了 html 错误响应。

      在某个时候,我让 IT 团队知道发生了什么。他们就像,让我们使 CloudFront 上的缓存无效......什么?!是的!让我们这样做......

      故事的寓意,如果您一直在网上搜索此错误的答案但找不到任何答案,请与 IT 团队或任何可能缓存 index.html 文件的地方联系。

      【讨论】:

        【解决方案8】:

        这可能意味着未处理的异常。您必须以任何您想要的方式处理来自服务器的错误响应(4xx、5xx 状态代码):在某处显示错误消息,重定向到某个页面,做任何事情,但不要让它处于未处理状态。

        例如:

        return this.http.get(requestDetails)
                  .map(res => res.json())
                  .catch(err => {
        console.log('server error:', err)
        Observable.throw(err);
        });
        

        【讨论】:

          猜你喜欢
          • 2019-12-07
          • 2018-12-20
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-25
          • 1970-01-01
          相关资源
          最近更新 更多