如何使用角度为4.3

时间:2017-09-02 19:06:51

标签: angular typescript angular-http angular-http-interceptors angular-httpclient

我有auth-interceptor.service.ts来处理请求

import {Injectable} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private router: Router) {}
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // Pass on the cloned request instead of the original request.
        return next.handle(authReq).catch(this.handleError);
    }

    private handleError(err: HttpErrorResponse): Observable<any> {
        console.log(err);
        if (err.status === 401 || err.status === 403) {
            Cookie.deleteUser();
            this.router.navigateByUrl(`/login`);
            return Observable.of(err.message);
        }
        // handle your auth error or rethrow
        return Observable.throw(err);
    }
}

但是我收到以下错误。没有任何事情真的发生,因为它没有删除cookie或它没有导航到登录页面 任何帮助或建议将不胜感激。

enter image description here

3 个答案:

答案 0 :(得分:23)

你应该使用你的拦截器并像这样处理它:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private router: Router) { }

    private handleAuthError(err: HttpErrorResponse): Observable<any> {
        //handle your auth error or rethrow
        if (err.status === 401 || err.status === 403) {
            //navigate /delete cookies or whatever
            this.router.navigateByUrl(`/login`);
            // if you've caught / handled the error, you don't want to rethrow it unless you also want downstream consumers to have to handle it as well.
            return Observable.of(err.message);
        }
        return Observable.throw(err);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // catch the error, make specific functions for catching specific errors and you can chain through them with more catch operators
        return next.handle(authReq).catch(x=> this.handleAuthError(x)); //here use an arrow function, otherwise you may get "Cannot read property 'navigate' of undefined" on angular 4.4.2/net core 2/webpack 2.70
    }
}

不需要http服务包装器。

要使用路由器,您需要一个工厂提供商,如:

 providers: [
     {
         provide: HTTP_INTERCEPTORS,
         useFactory: function(router: Router) {
           return new AuthInterceptor(router);
         },
         multi: true,
         deps: [Router]
      },
      .... other providers ...
  ]

你在哪里提供拦截器(可能是app.module)。不要使用箭头功能。当您尝试构建prod时,它们在工厂函数中不受支持。

工作插件:https://plnkr.co/edit/UxOEqhEHX1tCDVPDy488?p=preview

答案 1 :(得分:4)

从@ bryan60建议我对他的解决方案做了一些改动

在app.module.ts中:

providers: [
     {
        provide: HTTP_INTERCEPTORS,
        useFactory: function(injector: Injector) {
            return new AuthInterceptor(injector);
        },
        multi: true,
        deps: [Injector]
    },
      .... other providers ...
]

并在auth-interceptor.service.ts中:

import {Injectable, Injector} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from './cookie.service';
import {Router} from '@angular/router';
import {UserService} from './user.service';
import {ToasterService} from '../toaster/toaster.service';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private injector: Injector) {}

    private handleError(err: HttpErrorResponse): Observable<any> {
        let errorMsg;
        if (err.error instanceof Error) {
            // A client-side or network error occurred. Handle it accordingly.
            errorMsg = `An error occurred: ${err.error.message}`;
        } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            errorMsg = `Backend returned code ${err.status}, body was: ${err.error}`;
        }
        if (err.status === 404 || err.status === 403) {
            this.injector.get(UserService).purgeAuth();
            this.injector.get(ToasterService).showError(`Unauthorized`, errorMsg);
            this.injector.get(Router).navigateByUrl(`/login`);
        }
        console.error(errorMsg);
        return Observable.throw(errorMsg);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Clone the request to add the new header.
        const authReq = req.clone({headers: req.headers.set(Cookie.tokenKey, Cookie.getToken())});
        // Pass on the cloned request instead of the original request.
        return next.handle(authReq).catch(err => this.handleError(err));
    }
}

如果你正在使用AOT构建试试:

export function authInterceptorFactory(injector: Injector) {
    return new AuthInterceptor(injector);
}

providers: [
         {
            provide: HTTP_INTERCEPTORS,
            useFactory: authInterceptorFactory,
            multi: true,
            deps: [Injector]
        },
          .... other providers ...
]

答案 2 :(得分:1)

上面的@bryan60答案工作正常,如果有任何一个像我这样的问题,请抓住下面的错误

return next.handle(authReq).catch(x=> this.handleAuthError(x));

使用do()处理错误(如果遇到catch()问题)

导入文件:

import 'rxjs/add/operator/do';

处理错误:

return next.handle(authReq)
 .do(
    success => {/*todo*/},
    err => {this.handleAuthError(authReq)}
    );
}

handleAuthError(err: any) {
    if(err.status === 401 || err.status === 403) {
    this.storageService.clear();
    window.location.href = '/home';
    }
}

我希望这对某人有所帮助。