【问题标题】:How to get body/content of request from the HttpErrorResponse? [Angular ErrorHandler]如何从 HttpErrorResponse 获取请求的正文/内容? [角度错误处理程序]
【发布时间】:2018-11-14 02:19:26
【问题描述】:

假设我向服务器发送了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 });
                });
        }
    }
}

【问题讨论】:

    标签: angular error-handling angular-errorhandler


    【解决方案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 调用中获取错误应该不难。

    【讨论】:

      【解决方案2】:

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

       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}],
      

      【讨论】:

        【解决方案3】:

        首先,您必须确认 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 }]
        

        让我知道你是否可以:)

        【讨论】:

          猜你喜欢
          • 2023-03-14
          • 1970-01-01
          • 2019-10-27
          • 2019-07-23
          • 2017-07-29
          • 1970-01-01
          • 2021-09-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多