APP_INITIALIZER는 "순환 종속성을 인스턴스화할 수 없습니다!리디렉션하는 사용자 지정 Http 공급자와 함께 사용할 경우 ApplicationRef_"
API 인증 오류를 처리하기 위해 사용자 지정 Http 공급자를 사용하고 있습니다.나의 CustomHttp에서는 API에서 401 상태 오류가 발생할 때 사용자를 로그인 페이지로 리디렉션해야 합니다.그것은 잘 작동합니다!
app.s.ts.
export function loadCustomHttp(backend: XHRBackend, defaultOptions: AppRequestOptions,
router: Router, dataHelper: DataHelperService) {
return new CustomHttp(backend, defaultOptions, router, dataHelper);
}
@NgModule({
// some declarations, imports, ...
providers: [
// some services ...
{
provide: Http,
useFactory: loadCustomHttp,
deps: [XHRBackend, RequestOptions, Router, DataHelperService]
}
});
커스텀 패키지
import { Injectable } from '@angular/core';
import { Http, RequestOptions, RequestOptionsArgs, ConnectionBackend, Request, Response } from '@angular/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { DataHelperService } from '../helpers/data-helper.service';
import { AuthStorage } from '../services/auth/auth-storage';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/empty';
@Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions,
private router: Router, private dataHelper: DataHelperService) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.request(url, options));
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.get(url, options));
}
post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.post(url, body, options));
}
put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.put(url, body, options));
}
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.delete(url, options));
}
intercept(observable: Observable<Response>): Observable<Response> {
return observable.catch((err, source) => {
let token = AuthStorage.getToken();
if (err.status === 401 && token && AuthStorage.isTokenExpired()) {
// token has expired -> redirecting user to login
AuthStorage.clearAll();
this.router.navigate(['auth/login']);
}
return Observable.throw(err);
});
}
}
그리고 나서, 저는 그것을 사용하려고 했습니다.APP_INITIALIZER불투명 토큰을 사용하여 앱을 초기화하는 데 필요한 설정을 가져옵니다.
app.s.ts.
@NgModule({
// some declarations, imports, ...
providers: [
// some services ...
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: (config: ConfigService) => () => config.load(),
deps:[ConfigService, Http],
multi: true
}
});
config.service.ts
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { AppSettings } from '../../environments/app-settings';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class ConfigService {
public settings:AppSettings;
constructor(private http:Http) { }
load() : Promise<AppSettings> {
let url = '/settings/';
var observable= this.http.get(url)
.map(res => res.json());
observable.subscribe(config => this.settings = config);
return observable.toPromise();
}
}
그러면 다음과 같은 오류가 발생합니다.
Uncaught Error: Provider parse errors:
Cannot instantiate cyclic dependency! ApplicationRef_: in NgModule AppModuleNgModuleProviderAnalyzer.parse @ provider_analyzer.js:291NgModuleCompiler.compile @ ng_module_compiler.js:54RuntimeCompiler._compileModule @ runtime_compiler.js:102RuntimeCompiler._compileModuleAndComponents @ runtime_compiler.js:65RuntimeCompiler.compileModuleAsync @ runtime_compiler.js:55PlatformRef_._bootstrapModuleWithZone @ application_ref.js:303PlatformRef_.bootstrapModule @ application_ref.js:285(anonymous function) @ main.ts:18__webpack_require__ @ bootstrap 0e2b412…:52(anonymous function) @ main.bundle.js:86665__webpack_require__ @ bootstrap 0e2b412…:52webpackJsonpCallback @ bootstrap 0e2b412…:23(anonymous function) @ main.bundle.js:1
사용자 지정 Http 제공자에 대해 코멘트를 달면 오류가 표시되지 않고,APP_INITIALIZER예상대로 작동합니다.만약 내가 그것을 제거한다면.RouterHttp 제공자 deps 선언에서, 나는 더 이상 오류가 없지만 나의ConfigService.load()함수를 두 번 호출합니다.
이 라우터 종속성이 이 순환 종속성 오류를 일으키는 이유를 아는 사람이 있습니까?어떻게 예방할 수 있습니까?ConfigService.load()함수를 두 번 호출하시겠습니까?
필요한 경우 오류를 재현하는 공용 저장소를 만들었습니다. https://github.com/haia212/AngularErrorTestProject
문제는Router비동기식으로 일부 경로를 로드할 수 있습니다.이것이 필요한 이유입니다.Http.당신의.Http에 의존하는Router그리고.Router에 의존하는Http각도 인젝터에서 이러한 서비스를 생성할 수 없습니다.
저도 비슷한 문제가 있었는데 해결책 중 하나는 주사를 놓는 것입니다.Injector서비스 대신 서비스를 제공하고 나중에 서비스를 제공합니다.
코드:
@Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions,
private injector: Injector, private dataHelper: DataHelperService) {
super(backend, defaultOptions);
}
public get router(): Router { //this creates router property on your service.
return this.injector.get(Router);
}
...
그래서 기본적으로, 당신은 필요하지 않습니다.Router예를 들면Http서비스.주사는 당신이 접근할 때 완료됩니다.router속성 - 사용자를 리디렉션하려는 경우에만 해당됩니다.router속성은 코드의 다른 부분에 대해 투명합니다.
문제가 해결되지 않으면 주입된 나머지 서비스에도 동일한 작업을 수행할 수 있습니다(통화할 서비스 제외).super).
라우터를 에서 제거하여 간단히 해결했습니다.deps선언:
{
provide: Http,
useFactory: loadCustomHttp,
deps: [XHRBackend, RequestOptions, DataHelperService]
}
그리고 다른 모든 것들은 그대로 유지됩니다.약간 마술처럼 느껴지지만 효과가 있습니다.
이것이 도움이 될 수도 있습니다. 제가 해결한 방법은 다음을 위한 전략을 변경하는 것입니다.CustomHttp클래스에서 대신 컴포지션을 사용합니다.
나의CustomHttp다음과 같이 보입니다.
@Injectable()
export class CustomHttp {
constructor(private http: Http) {}
이제 사용자 지정 Http 서비스에 라우터나 다른 서비스를 삽입할 필요가 없습니다.
구성 로더(config.service.ts) 다음과 같이 변경했습니다.
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { AppSettings } from '../../environments/app-settings';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class ConfigService {
public settings:AppSettings;
constructor() { }
load(http: Http) : Promise<AppSettings> {
let url = '/settings/';
var observable= http.get(url)
.map(res => res.json());
observable.subscribe(config => this.settings = config);
return observable.toPromise();
}
}
주사할 필요가 없어졌습니다.Http에 추가했습니다.load(http: Http)방법.
내 안에서app.module.ts다음 항목이 있습니다.
providers: [
{
provide: Http,
useFactory: (backend, options) => new CustomHttp(new Http(backend, options)),
deps: [XHRBackend, RequestOptions]
},
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: (config, http) => () => config.load(http),
deps: [ConfigService, Http],
multi: true
},
이것은 제가 현재 앱에서 사용하고 있는 것입니다.이 방법이 당신에게 효과가 있을지는 모르겠지만 도움이 되기를 바랍니다.
언급URL : https://stackoverflow.com/questions/39767019/app-initializer-raises-cannot-instantiate-cyclic-dependency-applicationref-w
'programing' 카테고리의 다른 글
| Spring Data 저장소의 사용자 정의 방법 구현 및 REST를 통해 노출 (0) | 2023.08.11 |
|---|---|
| SQL Server 로그인을 코드에 저장(C#) (0) | 2023.08.11 |
| MySQL - INSERT 문 안에서 문자열 값을 DATTIME 형식으로 구문 분석하는 방법은 무엇입니까? (0) | 2023.08.06 |
| Android 리소스/값에 부동 소수점 값 추가 (0) | 2023.08.06 |
| 도커가 도커 레지스트리 서버에 이미 로그인되어 있는지 확인하는 방법 (0) | 2023.08.06 |