Angular HttpInterceptor-注入的任何服务均返回未定义的TypeError [英] Angular HttpInterceptor - Any Service Injected returns Undefined TypeError

查看:71
本文介绍了Angular HttpInterceptor-注入的任何服务均返回未定义的TypeError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

我无法将任何服务注入到HttpInterceptors的构造函数中.我尝试注入该服务的任何服务均遇到以下错误:

I'm unable to inject ANY service into the constructor of my HttpInterceptors. Any service that I attempt to inject into the service is met with the following error:

TypeError:无法设置未定义的属性'authenticationService'

这甚至适用于具有单个功能 bar 且没有其他依赖项注入的虚拟 foo 服务.

This goes for even a dummy foo service with a single function bar and no additional dependency injected into it.

代码

interceptor.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

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

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 { }

对于质疑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

已执行研究/故障排除:

我发现了各种SO帖子,并其他论坛帖子描述了注入服务时的问题包含HttpClient引用的引用将导致循环依赖项错误,导致未定义,并且authenticationService DOES具有对HTTPClient的引用.但是,根据帖子所述,此问题已在Angular 5修补程序中修复.如您所见,我目前正在为此项目使用Angular 7.

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. However, according to the posts, this was fixed in an Angular 5 patch. As you can see, I'm currently using Angular 7 for this project.

我试图遵循这些说明,而不是将 authenticationService 注入到构造函数中,而是注入一个Injector然后执行:

I have attempted to follow these instructions and instead of injecting the authenticationService into the constructor, injecting an Injector and then performing:

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

这会导致错误:

TypeError:无法设置未定义的属性"injector"

我还尝试将HttpInterceptor的app.module.ts提供程序更改为以下内容:

I've also tried to change the app.module.ts provider for the HttpInterceptor to the following:

{提供:HTTP_INTERCEPTORS,useFactory:拦截器,multi:true,deps:[AuthenticationService]}

这又导致了相同的未定义错误.

This resulted in, yet again, the same undefined error.

结论:

为小说道歉,但我想确保每个人都有所有可能的信息来帮助解决这个使我头痛3天的问题.预先谢谢大家!

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!

推荐答案

我遇到了同样的问题,我通过在声明中从 useFactory 切换为 useClass 来解决模块的

I had the same problem of yours and I solved by switching from useFactory to useClass in the declaration of the module:

这是有效的Angular 7.1代码

This was a working Angular 7.1 code

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

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

在Angular 8中已损坏.扔掉工厂即可解决问题:

which is broken in Angular 8. Throwing away the factory solves the issue:

{
    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.

这篇关于Angular HttpInterceptor-注入的任何服务均返回未定义的TypeError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆