插入拦截器后未定义Angular 6服务

时间:2018-09-04 11:46:54

标签: angular angular6

我找不到将 AuthService 注入 ErrorHandlerInterceptor 内的任何方法。 注入后返回一个“ undefined ”对象,或者引发错误。

这是我的 ErrorHandlerInterceptor

import { Injectable } from '@angular/core';
import { AuthService } from '@app/auth.service';
import { StorageService } from '@app/storage.service';

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

  constructor(private authService: AuthService, private storageService: StorageService) {
    console.log(this.authService); // undefined
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => this.errorHandler(error)));
  }

  // Customize the default error handler here if needed
  private errorHandler(response: HttpErrorResponse): Observable<HttpEvent<any>> 
  {
    // ... Various code
  }
}

这是我的 AuthService

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { StorageService } from './storage.service';
import { Router } from '@angular/router';

@Injectable({
    providedIn: 'root'
})
export class AuthService {
    constructor(private _http: HttpClient, 
    private storageService: StorageService, 
    private router: Router) { }
}

我试图在core.module.ts提供者中列出服务,但抛出错误:

ERROR RangeError: Maximum call stack size exceeded
at setCurrentInjector (core.js:1382)
at resolveNgModuleDep (core.js:8333)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)
at resolveNgModuleDep (core.js:8356)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)
at resolveNgModuleDep (core.js:8356)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)

请注意,我正在使用ngx-rocket创建的框架ngx-rocket-generator

如何解决此问题?有什么建议吗?


更新1-CORE.MODULE.TS

这是core.module.ts文件。

import { NgModule, Optional, SkipSelf } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { ShellComponent } from './shell/shell.component';
import { HeaderComponent } from './shell/header/header.component';
import { RouteReusableStrategy } from './route-reusable-strategy';
import { AuthenticationService } from './authentication/authentication.service';
import { AuthenticationGuard } from './authentication/authentication.guard';
import { I18nService } from './i18n.service';
import { HttpService } from './http/http.service';
import { HttpCacheService } from './http/http-cache.service';
import { ApiPrefixInterceptor } from './http/api-prefix.interceptor';
import { ErrorHandlerInterceptor } from './http/error-handler.interceptor';
import { CacheInterceptor } from './http/cache.interceptor';
import { TokenInterceptor } from './http/token.interceptor';
import { StorageService } from '@app/storage.service';
import { AuthService } from '@app/auth.service';

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    TranslateModule,
    NgbModule,
    RouterModule
  ],
  declarations: [
    HeaderComponent,
    ShellComponent
  ],
  providers: [
    AuthenticationService,
    AuthenticationGuard,
    I18nService,
    HttpCacheService,
    ApiPrefixInterceptor,
    ErrorHandlerInterceptor,
    CacheInterceptor,
    TokenInterceptor,
    {
      provide: HttpClient,
      useClass: HttpService
    },
    {
      provide: RouteReuseStrategy,
      useClass: RouteReusableStrategy
    }
  ]
})
export class CoreModule {

  constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
    // Import guard
    if (parentModule) {
      throw new Error(`${parentModule} has already been loaded. Import Core module in the AppModule only.`);
    }
  }

}

5 个答案:

答案 0 :(得分:2)

您传递给catchError函数的函数中没有注入的构造函数变量。您需要像这样在“拦截方法”中直接访问router

constructor(private router: Router) {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
        catchError((errorResponse: HttpErrorResponse) => {
            // this.router is defined here
        })
    );
}

问题似乎出在catchError之内。如果在thisintercept函数中同时打印当前作用域catchError,则分别得到 MyInterceptor CatchSubscriber this.router在CatchSubscriber中不可用。您仍然可以通过在拦截器类中添加私有方法来使用单独的功能:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
        catchError((errorResponse: HttpErrorResponse) => {
            this.handleError(errorResponse);
        })
    );
}

private handleError(errorResponse: HttpErrorResponse) {
     // this.router is defined here
}

总结:

catchError(this.handleError)  // does not work because of different scope

catchError(err => this.handleError(err))  // works because of same scope

答案 1 :(得分:2)

看起来,就像您必须为拦截器添加依赖项一样。在app.module.ts中,而不是仅在provide节中ErrorHandlerInterceptor声明您的提供者是这样的:

{
  provide: HTTP_INTERCEPTORS,
  useClass: ErrorHandlerInterceptor,
  multi: true ,
  deps: [AuthService, StorageService]
},

请注意,deps中的服务顺序应该与构造函数中的顺序相同。

PS。不确定Angular 6,但对于Angular 8,9来说,它的工作效果很好。

答案 2 :(得分:1)

最后,我解决了这个问题。 在错误处理程序中,不能通过构造函数注入依赖项。 要解决它,您需要执行以下操作:

首先,从@angular/core和您的服务导入Injector:

import { Injector } from '@angular/core';
import { AuthService } from '@app/auth.service';

然后,您必须将其注入到构造函数中:

constructor(private modalService: NgbModal, private injector: Injector) { }

然后您必须实例化服务并像这样使用它:

const authService = this.injector.get(AuthService);
authService.logout();

代码将与此类似:

import { Injector } from '@angular/core';
import { Router } from '@angular/router';

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

  private authService: AuthService;

  constructor(private modalService: NgbModal, private router: Router, private injector: Injector) { }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => this.errorHandler(error)));
  }

  // Customize the default error handler here if needed
  private errorHandler(response: HttpErrorResponse): Observable<HttpEvent<any>> {
    this.authService = this.injector.get(AuthService);
    ... Other code ...
}

希望这个答案对您有所帮助!

答案 3 :(得分:0)

我遇到了这个确切的问题,并尝试在错误处理程序中使用Injector的解决方案,但这对我也不起作用。我的服务或注入器都没有在我的错误处理程序中定义。我尝试了很多事情,但是对我有用的是使用匿名函数而不是编写新函数。我意识到在我的拦截函数中我的服务可用,但是转移到新函数时却导致它变得不确定。无论出于何种原因,使用匿名函数都会使我的服务保持在范围内。

在我的代码下面,有问题的服务是GlobalMessagesService。希望这可以帮助其他人度过这个头痛。

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { Router } from "@angular/router";

import { environment } from '../../environments/environment';
import { GlobalMessagesService } from '../global-messages/global-messages.service';    

@Injectable()
export class CustomHTTPSettings implements HttpInterceptor {

constructor(
    private router: Router,
    private MessagesService: GlobalMessagesService
) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    request = request.clone({
        setHeaders: headers
    });

    return next.handle(request).pipe(
        catchError((error: HttpErrorResponse) => { // this has to be inline or for some reason services aren't available


            if (environment.production != true) {
                console.error(error);
            }

            switch (error.status) {
                case 401:
                    this.router.navigate(['/login']);
                    return of(error);

                case 500:
                    this.MessagesService.addGlobalMessage({
                        message: 'Oops something went wrong. Please try again',
                        color: 'red'
                    });
                    throw error;
            }

        }) as any // then handle the error
    );
}

}

答案 4 :(得分:0)

我在github - Service with http call in constructor is injected as undefined in HttpInterceptor

中找到了解决方案
static translateService;

constructor(translateService: TranslateService) {
    ErrorInterceptor.translateService = translateService;
}
相关问题