Angular:全局错误处理程序只能运行一次

时间:2017-06-04 16:05:57

标签: angular

我有一个调用REST API的服务。 create操作POST参数,然后使用HTTP标头中返回的id获取创建的对象。返回对象时,Subject会传播该对象以通知其他组件。您可以注意到我没有调用catch操作。我故意这样做,所以全局错误处理程序管理错误它第一次按预期工作,但第二次,不调用全局错误处理程序。

在Chrome控制台中,我在第一次通话后收到错误,但在rxjs/Subscriber.js第二次通话后没有收到错误:

Subscriber.js:240 Uncaught 
Response {_body: "{"message":"The query is not valid"}", status: 500, ok: false, statusText: "Internal Server Error", headers: Headers…}

SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
        try {
            fn.call(this._context, value);
        }
        catch (err) {
            this.unsubscribe();
            throw err;
        }
    };

服务:

@Injectable()
export class SystemService {

  private subject = new Subject<any>();

  constructor(private http: Http) {
  }

  create(system: SdqlSystem) {
    this.http.post(environment.apiEndpoint + 'systems', system)
      .flatMap(res => {
        const location = res.headers.get('Location');
        return this.http.get(location);
      })
      .map(res => res.json())
      .subscribe(data => this.subject.next(data));

  }

  get(id: string) {
    this.http.get(environment.apiEndpoint + 'systems/' + id)
      .map(res => res.json())
      .subscribe(data => this.subject.next(data));
  }

  systems(): Observable<any> {
    return this.subject.asObservable();
  }

}

来自表格的电话:

onSubmit({value, valid}: { value: SdqlSystem, valid: boolean }) {
  this.systemService.create(value);
}

全局错误处理程序:

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  constructor(private logger: LoggingService, private notificationsService: NotificationsService) {
  }

  handleError(error: Response | any): void {
    console.log('***** HANDLE ERROR *****');
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || body.message || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    this.logger.error(errMsg);
    this.notificationsService.error('Error', errMsg);
    throw error;
  }

}

1 个答案:

答案 0 :(得分:6)

OP已经解决了,但我想我会回答以防其他人偶然发现这个问题:

重新考虑GlobalErrorHandler中的错误会导致浏览器停止执行的未捕获异常。这就是它只运作一次的原因 解决方案只是不要重新抛出ErrorHandler。

更多细节:在这种情况下,onError中没有提供subscribe() - 函数。这就是rxjs/Subscriber.js遇到catch - __tryOrUnsub部分的原因。 它尝试执行onError - 函数但失败(因为没有),因此取消订阅Observable并抛出错误。 GlobalErrorHandler选择它,进行记录和通知,然后重新抛出它 此时,错误成为Angular之外的未捕获异常。 (默认ErrorHandler不会重新抛出错误

注意:此方法适用于标准的http调用,因为Response-Observable只发出一个值,然后仍然完成。 如果你有一个需要发出多个值的Observable,你将不得不以不同的方式处理错误,因为发出错误的Observable不会发出任何其他值,如Observable-Contract中所述:

  

<强>的OnError
    表示Observable已终止指定的错误条件,表示不会发出更多项目