2017-06-06 187 views
21

我想在Angular 4中創建HTTP攔截器,但我有一些奇怪的錯誤。以下是我的錯誤:Angular 4 - HTTP攔截器

Argument of type 'Observable<Response>' is not assignable to parameter of type 'Observable<Response>'. 

以下是我的代碼:

import { Injectable } from '@angular/core'; 
 
import { Http, ConnectionBackend, RequestOptions, RequestOptionsArgs } from '@angular/http'; 
 
import { Router } from '@angular/router'; 
 
import { Observable } from 'rxjs/Observable'; 
 
import * as _ from 'lodash'; 
 

 
@Injectable() 
 
export class HttpInterceptor extends Http { 
 

 
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router) { 
 
     super(backend, defaultOptions); 
 
    } 
 

 
    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { 
 
     return this.intercept(super.request(url, options)); // Here is the error 
 
    } 
 

 
    get(url: string, options?: RequestOptionsArgs): Observable<Response> { 
 
     return this.intercept(super.get(url, options)); // Here is the error 
 
    } 
 

 
    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { 
 
     return this.intercept(super.post(url, body, this.getRequestOptionArgs(options))); // Here is the error 
 
    } 
 

 
    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { 
 
     return this.intercept(super.put(url, body, this.getRequestOptionArgs(options))); // Here is the error 
 
    } 
 

 
    delete(url: string, options?: RequestOptionsArgs): Observable<Response> { 
 
     return this.intercept(super.delete(url, options)); // Here is the error 
 
    } 
 

 
    getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs { 
 
     if (options == null) { 
 
      options = new RequestOptions(); 
 
     } 
 
     if (options.headers == null) { 
 
      options.headers = new Headers(); // Here is the error 
 
     } 
 
     options.headers.append('Content-Type', 'application/json'); 
 
     return options; 
 
    } 
 

 
    intercept(observable: Observable<Response>): Observable<Response> { 
 
     return observable.catch((err, source) => { 
 
      if (err.status == 401 && !_.endsWith(err.url, 'api/auth/login')) { 
 
       this._router.navigate(['/login']); 
 
       return Observable.empty(); 
 
      } else { 
 
       return Observable.throw(err); 
 
      } 
 
     }); 
 

 
    } 
 

 
}

有誰知道是怎麼回事錯在這裏?我嘗試了3個小時的調試,但無法找到任何線索。

編輯:

我也試圖去除一切,這樣寫代碼:

request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { 
 
    return super.request(url, options); 
 
}

但仍然是讓同樣的錯誤:

Argument of type 'string | Request' is not assignable to parameter of type 'string | Request'. Type 'Request' is not assignable to type 'string | Request'.

+0

這是因爲Observable.empty()不是可觀察的。 – Supamiu

+0

好吧,我只是試圖刪除一切,只寫: 'request(url:string | Request,options ?: RequestOptionsArgs):Observable { return super.request(url,options); }' 但它仍然給出相同的錯誤: '類型'字符串的參數|請求「不能分配給類型爲」string |「的參數請求'。 類型'請求'不可分配給'string | Request'.' –

回答

36

Http攔截器已在Angular 4.3.4中實現,並在documentation中進行了描述。

您需要執行intercept方法的HttpInterceptor接口,對請求做些什麼,並調用next.handle(req)方法。

import {Injectable} from '@angular/core'; 
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http'; 

@Injectable() 
export class NoopInterceptor implements HttpInterceptor { 
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
    const changedReq = req.clone({headers: req.headers.set('My-Header', 'MyHeaderValue')}); 
    return next.handle(changedReq); 
    } 
} 

這也是必要的應用程序的供應商部分註冊攔截

import {NgModule} from '@angular/core'; 
import {HTTP_INTERCEPTORS} from '@angular/common/http'; 

@NgModule({ 
    providers: [{ 
    provide: HTTP_INTERCEPTORS, 
    useClass: NoopInterceptor, 
    multi: true, 
    }], 
}) 
export class AppModule {} 
+14

值得注意的是,你必須使用HttpClient服務而不是Http服務。 https://angular.io/guide/http#httpclient –

+0

難道它不會攔截OPTIONS請求嗎? – Stefan

+0

@Stefan如果是OPTIONS,你可以檢查請求方法並調用next.handle。 'if(req.method ==='OPTIONS')' – akn

3

全局可用的DOM類型(您的tsconfig中的"lib": ["dom"])包括與Angular使用的類型無關的接口ResponseRequest

您需要從@angular/http導入ResponseRequest

+0

我也面臨同樣的問題,像Sahil,我不知道如何添加在「tsconfig.json」下面是我的文件 { 「compileOnSave」:false, 「compilerOptions」:{ 「OUTDIR」: 「./dist/out-tsc」, 「的baseUrl」: 「SRC」, 「sourceMap」:真實, 「宣言」:假的, 「moduleResolution」: 「節點」, 「emitDecoratorMetadata 「:真, 「experimentalDecorators」:真, 「目標」: 「ES5」, 「typeRoots」:[ 「node_modules/@類型」 ], 「LIB」:[ 「es2016」 , 「dom」 ] } } – Velkumar

+1

您不必觸摸tsconfig.json。 – dbandstra

+0

@Velkumar我剛剛在我的導入中導入了Response和Request。它解決了我的問題。 –

14

AKN的答案是正確的。我試圖使它與http服務,但攔截器只適用於惠特httpClient服務。

import { HttpClient } from '@angular/common/http'; 

constructor(private http: HttpClient) { } 
2

下列指示爲我工作完美:

在應用模塊:

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; 
import { myInterceptor} from './Interceptors/myInterceptor'; 

@NgModule({ 
    imports: [ 
... 
    HttpClientModule, 
    ], 
    providers: [{ 
    provide: HTTP_INTERCEPTORS, 
    useClass: MyInterceptor, 
    multi: true 
    }], 
    bootstrap: [AppComponent] 
}) 

在攔截器:

import { Injectable } from '@angular/core'; 

import { 
    HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse 
} from '@angular/common/http'; 

import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/do'; 
import { HttpErrorResponse } from '@angular/common/http'; 
import { RequestOptions } from '@angular/http'; 
import { HttpHeaders } from '@angular/common/http'; 

@Injectable() 
export class MyInterceptor implements HttpInterceptor { 
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
    // when there is POST request 
    if (req.method === 'POST') { 
     const content_type = 'application/x-www-form-urlencoded'; 
     const req= req.clone({ 
     headers: req.headers.set('Content-Type', content_type), 
     body: 'my body' 
     }); 

     return next.handle(accessReq); 
    } 
    } 
} 

重要:HTTP建議立即進行刪除d是HttpClient的一個實例!

constructor(
    private http: HttpClient, private accessTokenService: AccessTokenService 
) { } 
    return this.http.post(ingestURL, null) 
     .map(res => { 
      return res; // data returned from interceptor 
     }); 
0

使用此邏輯在任何框架中攔截Ajax。

private bootstrapAjaxInterceptor() { 
const _self = this; 
const originalOpen = XMLHttpRequest.prototype.open; 
XMLHttpRequest.prototype.open = function (xhrMethod, requestUrl) { 
    this.addEventListener('readystatechange', xhr => { 
    switch (this.readyState) { 
     case 1: _self.onAjaxStart(xhrMethod, requestUrl); break; 
     case 4: _self.onAjaxStop(this.responseURL, this.response); break; 
     default: // Nothing to handle here 
    } 
    }, false); 
    originalOpen.apply(this, arguments); 
}; 

}

下面是角完整的例子。

import { Injectable } from '@angular/core'; 
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 
interface AjaxRequest { 
    url?: string; 
    requestCount?: number; 
    method?: string; 
} 
interface AjaxResponse { 
    url?: string; 
    requestCount?: number; 
    response?: string; 
} 
@Injectable() 
export class HttpInterceptor { 
    public ajaxStart = new BehaviorSubject<AjaxRequest>({}); 
    public ajaxStop = new BehaviorSubject<AjaxResponse>({}); 
    private requestQueue: Array<any> = []; 
    constructor() { 
    this.bootstrapAjaxInterceptor(); 
    } 
    public getRequestQueue() { 
    return this.requestQueue; 
    } 
    private bootstrapAjaxInterceptor() { 
    const _self = this; 
    const originalOpen = XMLHttpRequest.prototype.open; 
    XMLHttpRequest.prototype.open = function (xhrMethod, requestUrl) { 
     this.addEventListener('readystatechange', xhr => { 
     switch (this.readyState) { 
      case 1: _self.onAjaxStart(xhrMethod, requestUrl); break; 
      case 4: _self.onAjaxStop(this.responseURL, this.response); break; 
      default: // Nothing to handle here 
     } 
     }, false); 
     originalOpen.apply(this, arguments); 
    }; 
    } 
    onAjaxStart(xhrMethod, requestUrl) { 
    this.requestQueue.push(requestUrl.replace(/\?.*/, '')); 
    this.ajaxStart.next({ 
     url: requestUrl, 
     requestCount: this.requestQueue.length, 
     method: xhrMethod 
    }); 
    } 
    onAjaxStop(responseURL, response) { 
    const responseUrl = responseURL.split(/\?/)[0]; 
    this.requestQueue.forEach((urlEndpoint, i) => { 
     if (new RegExp(`${urlEndpoint}$`).test(responseUrl)) { 
     return this.requestQueue.splice(i, 1); 
     } 
    }); 
    this.ajaxStop.next({ 
     url: responseUrl, 
     requestCount: this.requestQueue.length, 
     response: response 
    }); 
    } 
}