Angular 2 - 错误处理

问题描述 投票:1回答:2

Angular 2 - 我的应用程序中有很多页面,每个页面中我都在调用后端服务。在这里,我的查询是如何创建一个常见的错误弹出组件,它将收集错误消息并在需要我的应用程序时显示弹出窗口。能帮忙找到解决方案吗?谢谢。

angular
2个回答
1
投票

这就是我在Angular 5中的表现,你可以在Angular2中做到类似,因为它并没有那么不同。我希望这能帮到您。在我的app.component.html中,我补充说:

<div class="mesaages">
  <div *ngIf="errorMessage" class="alert alert-danger alert-dismissible fade show" role="alert">
      <button type="button" class="close" (click)="errorMessage=''">
                          <span aria-hidden="true">&times;</span> 
                      </button>
      <i class="fa fa-exclamation-circle fa-1x" aria-hidden="true"></i> {{ errorMessage}} 
  </div>

  <div *ngIf="busyinfoMessage" class="alert alert-success alert-dismissible fade show" role="alert">
      <button type="button" class="close" (click)="busyinfoMessage=''">
                          <span aria-hidden="true">&times;</span>
                      </button>
      <i class="fa fa-spinner fa-pulse fa-1x fa-fw" aria-hidden="true" placement="right"></i> {{ busyinfoMessage}}
  </div>

  <div *ngIf="infoMessage" class="alert alert-info alert-dismissible fade show" (mouseover)="stopTimeout('w')" (mouseout)="_actionService.infoMessage(infoMessage,3)" role="alert">
      <button type="button" class="close" (click)="infoMessage=''">
                          <span aria-hidden="true">&times;</span>
                      </button>
      <i class="fa fa-info-circle fa-1x" aria-hidden="true" placement="right"></i> {{ infoMessage}}
  </div>

  <div *ngIf="warningMessage" class="alert alert-warning alert-dismissible fade show" (mouseover)="stopTimeout('w')" (mouseout)="_actionService.warningMessage(warningMessage,3)" role="alert">
    <button type="button" class="close" (click)="warningMessage=''">
                        <span aria-hidden="true">&times;</span>
                    </button>
    <i class="fa fa-bell fa-1x" aria-hidden="true"></i> {{ warningMessage}}
</div>

在我的CSS文件中,我添加了这个:

.messages {
  float: left;
  top: 10px;
  right: 10px;
  width: 100;
  height: 20;
  padding: 6px;
  position: fixed;
  border-radius: 8px;
  z-index: 9999;
}

这个css代码会在页面右上角放置这个类似toast的消息。然后我创建了action.service.ts,用于显示此消息并切换我的loader-spinner:

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

@Injectable()
export class ActionService {
    public autoloader = true;
    public _toggleLoader: EventEmitter<any>;
    public _errorMessage: EventEmitter<any>;
    public _busyinfoMessage: EventEmitter<any>;
    public _warningMessage: EventEmitter<any>;
    public _infoMessage: EventEmitter<any>;
    public timeoutInfo: any;
    public timeoutWarning: any;

    constructor() {
        this._toggleLoader = new EventEmitter<any>();
        this._errorMessage = new EventEmitter<any>();
        this._busyinfoMessage = new EventEmitter<any>();
        this._warningMessage = new EventEmitter<any>();
        this._infoMessage = new EventEmitter<any>();
    }

    toggleLoader(toggle: boolean) {
        this._toggleLoader.emit(toggle);
    }

    errorMessage(errorMessage: string) {
        this._errorMessage.emit(errorMessage);
    }

    busyinfoMessage(busyinfoMessage: string) {
        this._busyinfoMessage.emit(busyinfoMessage);
    }

    warningMessage(warningMessage: string, timeout: number) {
        if (timeout === 0) {
            this._warningMessage.emit(warningMessage);
            return;
        }
        this.timeoutWarning = setTimeout(() => {
            this._warningMessage.emit('');
        }, 1000 * timeout);
        this._warningMessage.emit(warningMessage);
    }

    infoMessage(infoMessage: string, timeout: number) {
        if (timeout === 0) {
            this._infoMessage.emit(infoMessage);
            return;
        }
        this.timeoutInfo = setTimeout(() => {
            this._infoMessage.emit('');
        }, 1000 * timeout);
        this._infoMessage.emit(infoMessage);
    }

    stopTimeout(tip: string) {
        if (tip === 'w') {
            clearTimeout(this.timeoutWarning);
        } else {
            clearTimeout(this.timeoutInfo);
        }
    }    
    }
}

我的app.component.ts文件我添加了这行代码:

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subject } from 'rxjs/Subject';

import { ActionService } from './action.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
  private ngUnsubscribe: Subject<any> = new Subject();
  public loader = false;
  public errorMessage = '';
  public warningMessage = '';
  public busyinfoMessage = '';
  public infoMessage = '';

  constructor(
    private _router: Router,
    private _actionService: ActionService
  ) {
  }

  ngOnInit() {
    this._actionService._toggleLoader
      .takeUntil(this.ngUnsubscribe)
      .subscribe(res => {
        setTimeout(() => this.loader = res, 0);
      });

    this._actionService._errorMessage
      .takeUntil(this.ngUnsubscribe)
      .subscribe(res => {
        this.errorMessage = res;
      });

    this._actionService._warningMessage
      .takeUntil(this.ngUnsubscribe)
      .subscribe(res => {
        this.warningMessage = res;
      });

    this._actionService._busyinfoMessage
      .takeUntil(this.ngUnsubscribe)
      .subscribe(res => {
        this.busyinfoMessage = res;
      });

    this._actionService._infoMessage
      .takeUntil(this.ngUnsubscribe)
      .subscribe(res => {
        this.infoMessage = res;
      });

  }

  stopTimeout(tip: string) {
    this._actionService.stopTimeout(tip);
  }

  ngOnDestroy() {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }
}

因为我正在使用Angular 5,所以我创建了这个错误拦截器,用于在每次调用后显示错误消息:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import { ActionService } from './action.service';
import { Router } from '@angular/router';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {

    constructor(
        private _actionService: ActionService,
        private _router: Router) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request)
            .catch((err: HttpErrorResponse, caught) => {
                if (err.status === 0) {
                    this._actionService.errorMessage('Check you connection to interent!');
                    return Observable.empty<HttpEvent<any>>();
                }
                if (err.status === 500) {
                    this._actionService.errorMessage('Server error : ' + err.error.ExceptionMessage);
                    return Observable.empty<HttpEvent<any>>();
                }
                if (err.status === 401 || err.status === 403) {
                    this._router.navigateByUrl('prijava');
                    return Observable.empty<HttpEvent<any>>();
                }
                this._actionService.errorMessage('Unknown error. Error message: ' + (err.error.ExceptionMessage || err.error.Message));
                return Observable.empty<HttpEvent<any>>();
            })
    }
}

export const ErrorInterceptorProvider = {
    provide: HTTP_INTERCEPTORS,
    useClass: ErrorInterceptor,
    multi: true
};

由于您使用的是Angular 2,因此我建议您创建HTTP.Service并实现对该服务中的错误的调用。像这样的东西:

import { Injectable, ReflectiveInjector } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { LocatorService } from './locator.service';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { ActionService } from './action.service';

import { Url } from './global';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class HttpService extends Http {
    private currentRequests: number;
    private _router: Router;
    private _actionService: ActionService;

    constructor(backend: XHRBackend, options: RequestOptions, router: Router) {
        let token = localStorage.getItem('token'); // your custom token getter function here
        options.url = Url + (options.url == null ? '' : options.url);
        options.headers.set('Authorization', `Bearer ${token}`);
        super(backend, options);
        this._actionService = LocatorService.injector.get(ActionService);
        this._router = router;
        this.currentRequests = 0;
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        let token = localStorage.getItem('token');
        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 ${localStorage.getItem('token')}`);
            options.url = Url + url;
        } else {
            // we have to add the token to the url object
            if (!options) {
                // let's make option object
                options = { headers: new Headers() };
            }
            options.headers.set('Authorization', `Bearer ${localStorage.getItem('token')}`);
            url.url = Url + url.url;
        }        
        if (this._actionService.autoloader) { this._actionService.toggleLoader(true); }
        return super.request(url, options)
            .catch(
            this.catchError(this)
            )
            .finally(() => {
                setTimeout(() => {                    
                    if (this._actionService.autoloader) { this._actionService.toggleLoader(false); }
                }, 100);
            }
            );
    }   

    private catchError(self: HttpService) {
        // we have to pass HttpService's own instance here as `self`
        return (res: Response) => {
            console.log(res);
            switch (res.status) {
                case 0:
                    this._actionService.errorMessage('Check your internet connection!');
                    return Observable.throw(null);
                case 500:
                    this._actionService.errorMessage('Server error : ' + res.json()['ExceptionMessage']);
                    return Observable.throw(null);
                case 401:
                case 403:
                    this._router.navigateByUrl('prijava');
                    return Observable.throw(null);
                default:
                    this._actionService.errorMessage('Unknown error. Error message: ' + (res.json()['ExceptionMessage'] || res.json()['Message']));
                    return Observable.throw(null);
            }
        };
    }
}

我希望就是这样。如果您需要任何澄清,请询问。我希望这能帮到您。


0
投票

对于错误的用户通知,我使用Angular Material。在运行http查询时。我使用Observable结果中的error =>箭头函数处理来自http observables的错误。例如,这是对我的restful API的身份验证登录查询。

...
constructor(private _dialogService: TdDialogService,
              private _viewContainerRef: ViewContainerRef,
              private authenticationService: AuthenticationService){}
       login() {
    this.authenticationService.login(this.formLogin.value.email, this.formLogin.value.password)
      .subscribe(
        data => {
          // Handle any 200 result
        },
        error => {
          // Handle any http errors, 401 UnAuthorized or 500 or any other
          this.openAlert('Invalid username or password'); // You can pass in your error message
        });
  }

  openAlert(message: string) {
    this._dialogService.openAlert({
      message,
      disableClose: true,
      viewContainerRef: this._viewContainerRef,
      title: 'Error',
      closeButton: 'Ok'
    });
  }
}

结果

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.