如何在 Angular 中的提供程序配置期间从 useFactory 函数进行 HTTP 调用?

How to make an HTTP call from useFactory function during provider configuration in Angular?

我有下一个提供商配置

  {
          provide: APP_INITIALIZER,
          useFactory: initializeKeycloak,
          multi: true,
          deps: [KeycloakService],
        },

如何从 useFactory 函数 (initializeKeycloak) 进行 HTTP 调用?

function initializeKeycloak(keycloak: KeycloakService) {

  return () =>
    keycloak.init({
      config: {
        url: environment.keycloak.url,
        realm: environment.keycloak.realm,
        clientId: environment.keycloak.clientId
      }
    });
}

我想从资产文件夹中获取这个值

environment.keycloak.url

这里有两件事你需要知道:

  • 在您的 asyncFactory 函数中,您可以 return 指示初始化何时完成的承诺。
  • 您可以将 HttpClient 添加到 APP_INITIALIZER 的依赖项中。请注意,您必须将 HttpClientModule 添加到 AppModule 的导入中,以便它可用于注入。

RxJS 6 的工作示例:

const initializeKeycloak = (
  keycloakService: KeycloakService,
  httpClient: HttpClient // The httpClient is available here because you added it to the deps of the APP_INITIALIZER
) => {
  return () =>
    httpClient
      .get(url)
      .pipe(
        tap((environment: any) => {
          keycloakService.init({
            config: {
              url: environment.keycloak.url,
              realm: environment.keycloak.realm,
              clientId: environment.keycloak.clientId
            }
          });
        })
      )
      .toPromise(); // Return the promise to indicate the initialization is done.
};

@NgModule({
  imports: [BrowserModule, FormsModule, HttpClientModule],
  declarations: [AppComponent, HelloComponent],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeKeycloak,
      multi: true,
      deps: [KeycloakService, HttpClient] // Add the HttpClient here.
    },
    KeycloakService
  ]
})
export class AppModule {}

RxJS 7+ 的工作示例(toPromise 将被弃用,您必须使用 lastValueFrom):

import { lastValueFrom } from "rxjs";
...

const initializeKeycloak = (
  keycloakService: KeycloakService,
  httpClient: HttpClient
) => {
  return () => {
    const request$ = httpClient.get(url).pipe(
      tap((environment: any) => {
        keycloakService.init({
          config: {
            url: environment.keycloak.url,
            realm: environment.keycloak.realm,
            clientId: environment.keycloak.clientId
          }
        });
      })
    );
    return lastValueFrom(request$);
  };
};

旁注:

虽然可以在启动时检索环境信息,但缺点是如果请求失败,应用根本不会加载。 在这里添加一个 retry mechanism.

可能是值得的

还有一些方法可以在构建时注入环境变量,我在 this answer 中提供了有关该主题的信息。