Как обработка ошибок HTTP работает с наблюдаемыми?

Я вижу много учебников, которые делают что-то вроде этого:

http.get("...").subscribe(
  success => console.log('hello success'),
  error => console.log('bye error')
);

Я не знаю, как это работает, так как нет никаких типов или чего-либо, однако Я пытался это сделать сам, и в итоге я уверен, что запрос всегда идет в успех, даже если У меня ошибка. В чем проблема?

Нарушитель

this.memberService.create(this.currentMember)
      .subscribe(
        success => {
          let mem: Member = success.json() as Member;
          if (this.selectedOrganization) {
            this.addMemberToOrganization(mem);
          } else if (this.selectedServiceProvider) {
            this.addMemberToServiceProvider(mem);
          } else {
            this.toastsService.error("lbl_users_service_provider_and_organization_undefined");
          }
        },
        error => console.log(error)
      );

Создать-метод в memberService:

  create(member: Member): Observable<any> {
    return this.http
      .post(this.RESOURCE_BASE_URL, member)
      .map(response => {
        if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));
        return response;
      })
      .catch(error => this.toastsSerivce.error(this.translateService.instant('lbl_users_member_create_failed')));
  }

Я даже поймаю ошибку, но часть subscribe, похоже, не заботится. Он терпит неудачу при success.json(), потому что, если есть ошибка, нет json. Но если есть ошибка, я хочу, чтобы она вызывала error =>... вместо success. Любые советы приветствуются.

Ответ 1

Я думаю, проблема в том, что вы не throwing ошибка с Observable.throw(errMsg).

Итак, вы можете просто использовать его следующим образом:

.catch((error:any) => Observable.throw(error.json().error || 'Server error'));

В вашем примере:

create(member: Member): Observable<any> {
    return this.http
      .post(this.RESOURCE_BASE_URL, member)
      .map(response => {
        if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));
        return response;
      })
      .catch((error:any) => Observable.throw(this.toastsSerivce.error(this.translateService.instant('lbl_users_member_create_failed'))));
  }

Но вы можете использовать обработчик ошибок, например, тот, который Angular предлагает здесь:

private handleError (error: Response | any) {
    // In a real world app, you might use a remote logging infrastructure
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }

Итак, ваш метод будет выглядеть примерно так:

create(member: Member): Observable<any> {
    return this.http
      .post(this.RESOURCE_BASE_URL, member)
      .map(response => {
        if (response.status === 200) this.toastsSerivce.success(this.translateService.instant('lbl_users_member_created'));
        return response;
      })
      .catch(this.handleError);
  }

Он действительно более чистый и многоразовый для других методов, которые вы можете создать в своей службе.

Я бы предложил использовать также обработчик ответа, например тот, который используется Angular devs: this.extractData.

Obviusly, внутри метода дескриптора ошибки вы можете поместить свою собственную логическую, в зависимости от того, как вы хотите показать или обработать ошибку.

ПРИМЕЧАНИЕ. Я не тестировал ваш код и код, который я разместил здесь. Но я хотел показать/выразить концепцию. Вы должны выбросить ошибку, чтобы не входить в success каждый раз. Как вы справляетесь с этим, это зависит от вас и вашего приложения.

Ответ 2

Это работает для меня:

this.http.post('http://example.com/path/', {sampleData: 'd'}).subscribe(
res => {alert('ok!');},
err => alert(err.error)
)