可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to create HTTP Interceptor in Angular 4 but I'm having some weird error. Following is my error:
Argument of type 'Observable<Response>' is not assignable to parameter of type 'Observable<Response>'.
Following is my Code:
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);
}
});
}
}
Does anyone know what is going wrong here? I tried debugging for 3 hours but unable to find any clue.
Edit:
I also tried to remove everything and written a code like this:
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return super.request(url, options);
}
But still it's giving same error:
Argument of type 'string | Request' is not assignable to parameter of type 'string | Request'. Type 'Request' is not assignable to type 'string | Request'.
回答1:
Http interceptor is already implemented in Angular 4.3.4 and is described in the documentation.
You need to implement the intercept
method of HttpInterceptor
interface, do something with the request, and call the next.handle(req)
method.
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);
}
}
It's also necessary to register interceptor in app's providers section
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: NoopInterceptor,
multi: true,
}],
})
export class AppModule {}
回答2:
akn's answer is the right one. I was trying to make it work with http service, but the interceptor only works whit httpClient service.
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) { }
回答3:
The globally available DOM typings ("lib": ["dom"]
in your tsconfig) include Response
and Request
interfaces that are unrelated to the types used by Angular.
You need to import Response
and Request
from @angular/http
.
回答4:
The following instruction worked for me perfectly:
In the app module:
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]
})
In the interceptor:
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);
}
}
}
IMPORTANT: http should be an instance of HttpClient!
constructor(
private http: HttpClient, private accessTokenService: AccessTokenService
) { }
return this.http.post(ingestURL, null)
.map(res => {
return res; // data returned from interceptor
});
回答5:
Use this logic to intercept Ajax in any framework.
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);
};
}
Here is complete example for Angular.
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
});
}
}