如何在Angular 4中初始化自定义服务类型的私有变量?

时间:2017-09-23 03:13:06

标签: angular typescript

我正在创建一个Angular4 Http的扩展类,这样我就可以通过添加auth头和处理身份验证失败的注销来管理这个顶层服务中的身份验证。这是服务,

import { Injectable } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { AuthService } from '../../auth/auth.service';

@Injectable()
export class HttpService extends Http {
    constructor(backend: XHRBackend, options: RequestOptions, private authService: AuthService) {
        super(backend, options);
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        let token = localStorage.getItem('accessToken');
        if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
            if (!options) {
                // let's make option object
                options = { headers: new Headers() };
            }
            options.headers.set('Authorization', `Bearer ${token}`);
        } else {
            // we have to add the token to the url object
            url.headers.set('Authorization', `Bearer ${token}`);
        }
        return super.request(url, options).catch(this.catchAuthError(this));
    }

    private catchAuthError(self: HttpService) {
        // we have to pass HttpService's own instance here as `self`
        return (res: Response) => {
            console.log(res);
            if (res.status === 401 || res.status === 403) {
                // if not authenticated
                console.log(res);
            }
            return Observable.throw(res);
        };
    }
}

我在我的app.module.ts文件中使用它如下。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// import { HttpModule } from '@angular/http';
import { HttpModule, RequestOptions, XHRBackend } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule } from '@angular/forms';
import { MdMenuModule } from '@angular/material';

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


// Services
import { AuthService } from './auth/auth.service';
import { AuthGuard } from './shared/auth-guard.service';

import { SharedModule } from './shared/shared/shared.module';
import { HttpService } from './shared/services/http.service';
export function uFact (backend: XHRBackend, options: RequestOptions) {
    return new HttpService(backend, options);
}
@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        HttpModule,
        AppRoutingModule,
        ReactiveFormsModule,
        SharedModule,
        BrowserAnimationsModule,
        MdMenuModule
    ],
    providers: [
        AuthService,
        AuthGuard,
        {
            provide: HttpService,
            useFactory: uFact,
            deps: [XHRBackend, RequestOptions]
        }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

我必须在AuthService的构造函数HttpService中添加private authService: AuthService。但它在app.module.ts中引发错误。我无法在导出的函数new HttpService(backend, options)中实例化uFact,因为它的构造函数中还需要一个参数。我怎么解决这个问题?我是Angular的新手。

2 个答案:

答案 0 :(得分:1)

您可以通过向&#39; deps&#39;添加Authservice来解决此问题。因为deps将帮助您将AuthService依赖项加载到HttpService。

  providers: [
    AuthService,
    AuthGuard,
    {
        provide: HttpService,
        useFactory: uFact,
        deps: [XHRBackend, RequestOptions,AuthService] // here
    }
],

.....

deps属性是provider tokens的数组,因此您在此处提及的服务将充当其自己的类的标记。注入器会解析这些标记并将相应的服务注入到匹配的工厂函数参数中。

如果您的HttpService构造函数存在问题,那么您可以将AuthService变量声明为可选。(构造函数(后端:XHRBackend,选项:RequestOptions,私有authService?:AuthService))。因此,编译器不会显示任何参数缺失错误。但它将来会引起错误。

答案 1 :(得分:0)

你可以把它写成:

constructor(backend: XHRBackend, options: RequestOptions) {
   super(backend, options);
   let token = localStorage.getItem('accessToken'); 
   options.headers.set('Authorization', `Bearer ${token}`);
}

在super之后设置标题应该没关系,因为在做出实际请求时会使用options