简体   繁体   English

Angular HttpInterceptor - 注入的任何服务都返回未定义的类型错误

[英]Angular HttpInterceptor - Any Service Injected returns Undefined TypeError

Problem:问题:

I'm unable to inject ANY service into the constructor of my HttpInterceptors.我无法将任何服务注入到我的 HttpInterceptors 的构造函数中。 Any service that I attempt to inject into the service is met with the following error:我尝试注入服务的任何服务都会遇到以下错误:

TypeError: Cannot set property 'authenticationService' of undefined

This goes for even a dummy foo service with a single function bar and no additional dependency injected into it.这甚至适用于具有单个功能bar且没有注入额外依赖项的虚拟foo服务。

THE CODE编码

interceptor.ts拦截器.ts

import { Injectable, Injector } from '@angular/core';
import {
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpInterceptor
} from '@angular/common/http';
import { AuthenticationService } from '../authentication/authentication.service';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class Interceptor implements HttpInterceptor {

    constructor(private authenticationService: AuthenticationService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (request.url.includes(location.hostname) && this.authenticationService.getToken()) {
            console.log('Headers added to the HTTP Request');
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${this.authenticationService.getToken()}`
                }
            });
        }
        return next.handle(request);
    }
}

authentication.service.ts身份验证.service.ts

import { OnInit, Injectable } from '@angular/core';
import { AuthServiceConfig, AuthService as SocialAuthService, FacebookLoginProvider, GoogleLoginProvider, SocialUser} from 'angularx-social-login';
import { HttpClient, HttpRequest } from  '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { environment } from '../../../environments/environment';
import { JwtHelperService } from '@auth0/angular-jwt';

@Injectable( { providedIn: "root" } )

export class AuthenticationService implements OnInit{

  jwtHelper: JwtHelperService = new JwtHelperService();
  socialLoginConfig: AuthServiceConfig;
  loggedIn: BehaviorSubject<Boolean> = new BehaviorSubject<Boolean>(false);
  loggedIn$: Observable<Boolean> = this.loggedIn.asObservable();
  user: BehaviorSubject<SocialUser> = new BehaviorSubject(null);
  user$: Observable<SocialUser> = this.user.asObservable();

  cachedRequests: Array<HttpRequest<any>> = [];

  constructor(private socialAuthService: SocialAuthService, private http: HttpClient) { }

  ngOnInit() {
    this.socialAuthService.authState.subscribe((user) => {
      this.user.next(user);
      this.loggedIn.next((user != null));
    });
  }

  provideConfig() {
    return this.socialLoginConfig;
  }

  getToken(): string {
    return localStorage.getItem('token');
  }

  refreshToken(): void {
    // Need to add a call to refresh the token (JWT) to the backend.
  }

  isAuthenticated(): boolean {
    const token = this.getToken();
    return token != null && !this.jwtHelper.isTokenExpired(token);
  }

  collectFailedRequest(request): void {
    this.cachedRequests.push(request);
  }

  retryFailedRequests(): void {
    // Once the token has been refreshed, we can send previous failed requests from the cahcedRequests array...
  }

  signInWithGoogle(cb): void {
    this.socialAuthService.signIn(GoogleLoginProvider.PROVIDER_ID).then(
      (userData) => { //on success
        console.log('google', userData);
        this.user.next(userData);
        this.sendToRestApiMethod(userData.idToken, 'google', cb);
      }
    ).catch(err => {
      console.log('Error logging into Google Services:', err);
    });
  }

  signInWithFB(cb): void {
    this.socialAuthService.signIn(FacebookLoginProvider.PROVIDER_ID).then(
      (userData) => { //on success
        console.log('facebook', userData);
        this.user.next(userData);
        this.sendToRestApiMethod(userData.authToken, 'facebook', cb);
      }
    ).catch(err => {
      console.log('Error logging into Facebook Services:', err);
    });
  }

  signOut(): void {
    this.socialAuthService.signOut();
    this.user.next(null);
  }

  sendToRestApiMethod(token: string, provider: string, cb) : void {
    this.http.post(environment.apiBaseUrl +'oauth2/authorization/' + provider, { token: token } )
      .subscribe(jwt => {
       console.log('login was successful', jwt);
       localStorage.setItem('token', jwt['jwt']);
       cb();
     }, onFail => {
        console.log('login was unsuccessful', onFail);
        //show an error message
     }
   );
 }
}

app.module.ts app.module.ts

import { environment } from '../environments/environment';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { LoginComponent } from './modules/public/pages/login/login.component';
import { SocialLoginModule, AuthServiceConfig } from "angularx-social-login";
import { GoogleLoginProvider, FacebookLoginProvider } from "angularx-social-login";

import { NavbarComponent } from './shared/components/navbar/navbar.component';
import { FooterComponent } from './shared/components/footer/footer.component';
import { HomeComponent } from './modules/public/pages/home/home.component';
import { UserComponent } from './modules/secure/pages/user/user.component';

import { HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';
import { Interceptor } from './core/interceptors/interceptor';
import { DashboardComponent } from './modules/secure/pages/dashboard/dashboard.component';

const socialLoginConfig = new AuthServiceConfig([
  { id: GoogleLoginProvider.PROVIDER_ID, 
    provider: new GoogleLoginProvider(environment.google.clientid) },
  { id: FacebookLoginProvider.PROVIDER_ID, 
    provider: new FacebookLoginProvider(environment.facebook.appid) }
]);

export function provideConfig() {
  return socialLoginConfig;
}
@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    LoginComponent,
    UserComponent,
    NavbarComponent,
    FooterComponent,
    DashboardComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    SocialLoginModule,
    HttpClientModule
  ],
  providers: [
    { provide: AuthServiceConfig, useFactory: provideConfig },
    { provide: HTTP_INTERCEPTORS, useFactory: Interceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

For people questioning the Angular version...对于质疑 Angular 版本的人...

Angular CLI: 7.2.3
Node: 11.7.0
OS: darwin x64
Angular: 7.2.2
... animations, cdk, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.12.3
@angular-devkit/build-angular     0.12.3
@angular-devkit/build-optimizer   0.12.3
@angular-devkit/build-webpack     0.12.3
@angular-devkit/core              7.2.3
@angular-devkit/schematics        7.2.3
@angular/cli                      7.2.3
@ngtools/webpack                  7.2.3
@schematics/angular               7.2.3
@schematics/update                0.12.3
rxjs                              6.3.3
typescript                        3.2.4
webpack                           4.28.4

Research/Troubleshooting Performed:进行的研究/故障排除:

I found various SO posts and other forum posts describing issues when injecting a service that contains a HttpClient reference will cause a cyclic dependency error leading to the undefined, and authenticationService DOES have a reference to HTTPClient.我发现各种 SO 帖子和其他论坛帖子描述了在注入包含 HttpClient 引用的服务时会导致循环依赖错误导致未定义的问题,并且 authenticationService 确实有对 HTTPClient 的引用。 However, according to the posts, this was fixed in an Angular 5 patch.但是,根据帖子,这是在 Angular 5 补丁中修复的。 As you can see, I'm currently using Angular 7 for this project.如您所见,我目前在这个项目中使用 Angular 7。

I have attempted to follow these instructions and instead of injecting the authenticationService into the constructor, injecting an Injector and then performing:我尝试按照这些说明进行操作,而不是将authenticationService注入构造函数,而是注入 Injector 然后执行:

this.authenticationService = this.injector.get(AuthenticationService);

This lead to the error:这导致错误:

TypeError: Cannot set property 'injector' of undefined

I've also tried to change the app.module.ts provider for the HttpInterceptor to the following:我还尝试将 HttpInterceptor 的 app.module.ts 提供程序更改为以下内容:

{ provide: HTTP_INTERCEPTORS, useFactory: Interceptor, multi: true, deps: [AuthenticationService] }

This resulted in, yet again, the same undefined error.这再次导致了相同的未定义错误。

Conclusion:结论:

Apologies for the novel, but I wanted to ensure everyone had all possible information to help solve this issue that's caused me 3 days worth of headaches.为这部小说道歉,但我想确保每个人都拥有所有可能的信息来帮助解决这个让我头疼三天的问题。 Thanks all in advance!提前谢谢大家!

I had the same problem of yours and I solved by switching from useFactory to useClass in the declaration of the module:我能有你同样的问题,我解决了从切换useFactoryuseClass在模块的声明:

This was a working Angular 7.1 code这是一个有效的 Angular 7.1 代码

{
    provide: HTTP_INTERCEPTORS,
    useFactory(router: Router, authenticationStorageService: AuthenticationStorageService) {
        // a lot of stuff here

        return new AuthInterceptor(router, authenticationStorageService);
    },
    multi: true,
    deps: [Router, AuthenticationStorageService]
},

which is broken in Angular 8. Throwing away the factory solves the issue:这在 Angular 8 中被破坏了。扔掉工厂解决了这个问题:

{
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true,
    deps: [Router, AuthenticationStorageService]
},

I had to shift the factory logic in the constructor of the class though.不过,我不得不在类的构造函数中移动工厂逻辑。 The factory approach was more flexible as you could change the returned instance from time to time, but probably an overkill in the standard case.工厂方法更灵活,因为您可以不时更改返回的实例,但在标准情况下可能有点矫枉过正。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM