0

假设我向post服务器发送了一个创建用户的请求。如果服务器响应错误,我想从ErrorHandler. 这样做的原因是,例如,当“创建用户”失败时,我想显示一个通知,其中包含从表单中获取的一些详细信息和一个按钮,用于将您重定向回相应的页面,并再次填充检索到的字段形式。

这就是我的ErrorHandler样子:

@Injectable()
export class ErrorsHandler implements ErrorHandler {
    constructor(
        private injector: Injector,
    ) { }

    handleError(error: Error | HttpErrorResponse) {
        const errorsService = this.injector.get(ErrorsService);
        const router = this.injector.get(Router);
        const zone = this.injector.get(NgZone);
        if (error instanceof HttpErrorResponse) {
            // Server error happened
            if (!navigator.onLine) {
                return console.log('No Internet Connection.');
            }
            else if (error.status === HttpStatus.UNAUTHORIZED) {
                console.log('ErrorsHandler handled HttpStatus Unauthorized. Navigating back to \'/login\' page.');
                zone.run(() => router.navigate(['/login']));
            }
            else {
                // Http Error
                //How do I get the form from here? I need it for user notification.
                return console.log('%c SERVER ERROR ', 'background: #222; color: #ff6961 ; font-size: 15px; border: 2px solid #ff6961;', error);
            }
        } else {
            // Client Error Happend
            // Send the error to the server and then
            // redirect the user to the page with all the info
            errorsService
                .log(error)
                .subscribe(errorWithContextInfo => {
                    router.navigate(['/error'], { queryParams: errorWithContextInfo });
                });
        }
    }
}
4

3 回答 3

1

我用拦截器对@GabrielLopez 的回答有所不同:

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse}
  from "@angular/common/http";
import {Observable, throwError} from "rxjs";
import {catchError, tap} from "rxjs/operators";

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>,
            next: HttpHandler):
        Observable<HttpEvent<any>> {
    return next.handle(req)
      .pipe(
        tap((ev: HttpEvent<any>) => {
          if (ev instanceof HttpResponse) {
            console.log(`processing response ${ev.status}`);
          }
        }),
        catchError(response => {
          console.log('Processing http error', response);
          if (response.error) {
            return throwError(response.error);
          } else if (response.message) {
            return throwError(response.message);
          } else {
            return throwError(response);
          }
        })
      );
  }
}

和加布里埃尔的回答一样,拦截器需要在 app.module.ts 中声明providers

@NgModule({
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpErrorInterceptor,
      multi: true
    },
    ...

我对此不满意,因为这可能意味着 Angular HttpClient 错误处理过度设计。从 REST API 调用中获取错误应该不难。

于 2019-02-28T10:25:13.267 回答
1

我认为从 HttpErrorResponse 实例中获取正文是不可能的,因为它扩展了 HttpResponseBase ,它不像普通的 HttpResponse 那样具有 body 属性。

 export declare class HttpErrorResponse extends HttpResponseBase implements Error {
    readonly name: string;
    readonly message: string;
    readonly error: any | null;
    /**
     * Errors are never okay, even when the status code is in the 2xx success range.
     */
    readonly ok: boolean;
    constructor(init: {
        error?: any;
        headers?: HttpHeaders;
        status?: number;
        statusText?: string;
        url?: string;
    });
}

我所做的是使用响应拦截器:

import { Injectable } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { ResponseBusiness } from '../Models/General/ResponseBusiness.model';
import { MsgService } from '../services/msg.service';
import { AlertService } from '../services/alert.service';

@Injectable()
export class ResponseInterceptor implements HttpInterceptor {
  constructor(private _msg: MsgService, private _alertService: AlertService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(req).map(resp => {

      const response = <HttpResponse<ResponseBusiness<Object>>> resp;

      if (resp instanceof HttpResponse) {
      }


      /* do whatever you need with the req.body */

      if (resp instanceof HttpErrorResponse) {
        const body = JSON.parse(req.body);
        if (body && body.avoidMsg) {
          return resp;
        }
      }

      if (response.status === 200 && !response.body.result.status) {
        this._msg.setMsg({message: `${response.body.result.codeNumber} ${response.body.result.codeDescription}`, tipo: 'error'});
      }
      return resp;
    });

  }
}

然后将 inteceptor 添加到您的 app.module 中,如下所示:

providers: [
    {provide: HTTP_INTERCEPTORS, useClass: ResponseInterceptor, multi: true}],
于 2018-11-14T02:58:23.063 回答
0

首先,您必须确认 BE 在正文中返回 JSON 错误。下一步您可以为您的想法自定义 HttpInterceptor,更多细节您可以通过关键字 angular httpinterceptor 搜索。

这是我的 HttpInterceptor 来源,可能会有一些帮助。

import { Injectable } from '@angular/core';
import { HttpRequest, HttpInterceptor, HttpHandler, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';

@Injectable()
export class SiteHttpInterceptor implements HttpInterceptor {
  constructor(
  ) {}

  intercept(request: HttpRequest<any>, httpHandler: HttpHandler): Observable<any> {
      let token = localStorage.getItem('token');
      if (('/api/users/token').indexOf(request.url) < 0 && token) {
          request = request.clone({
              setHeaders: {
                  'authorization': 'bearer ' + token,
                  'Authenticationtoken': 'bearer ' + token
              }
          });
      }

      return httpHandler.handle(request).pipe(
          tap((event: HttpEvent<any>) => {
              //success
          },
          (err: any) => {
              //error
          }),
          catchError(err => {
              if (err.status === 401) {
                  // if you want to do sth. when 401 can code here
              } else {
                  // other
              }
              return throwError(err);
          })
      );
  }
}

并将 HttpInterceptor 设置为 app.module.ts

import { SiteHttpInterceptor } from './providers/http-interceptor';
@NgModule({
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }]

让我知道你是否可以:)

于 2018-11-14T02:56:55.327 回答