javascript - 根据错误状态代码重定向到 Angular 中的组件

标签 javascript angular typescript error-handling

我正在处理四个部分的错误......服务器返回错误的 http 拦截器,一个基于内置 Angular 错误处理程序的全局错误处理程序。将错误记录到后端服务以提供支持的错误服务以及用于向最终用户显示友好消息的 Material 对话框组件。

有一些错误我们希望捕获错误状态代码并重定向到组件以获得更友好的最终用户体验。

一个例子是 404。我们有一个未找到的组件。如果服务器错误状态为 404,我想重定向到未找到的组件并且不显示错误对话框。

这是我的拦截器...

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import * as StackTrace from 'stacktrace-js';
import { ErrorDialogComponent } from './error-dialog.component';
import { PathLocationStrategy } from '@angular/common';
import { ErrorService } from './error.service';
import { LoggerService } from './logger.service';
import { Router } from '@angular/router';

@Injectable()
/**
 * HttpErrorInterceptor to grab errors during http calls and log them
 *
 * @param (clientId) client id
 */
export class HttpErrorInterceptor implements HttpInterceptor {
  /**
   * constructor to grab errors during http calls and log them
   *
   * @param (dialog) MAT dialog to display to end user
   * @param (errorService) error service to grab error messages
   * @param (logger) logger service to post log errors to api and mantis
   */
  constructor(
    public dialog: MatDialog,
    private errorService: ErrorService,
    private logger: LoggerService,
    private router: Router
  ) {}
  /**
   * Interecept to grab request, deal with it and pass it along
   *
   * @param (request) http request
   * @param (next) send request to next http handler
   */
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // return the next statement
    return next.handle(request).pipe(
      // retry the call once
      retry(1),
      // catch the error
      catchError((error: HttpErrorResponse) => {
        if (error.status === 404) {
          console.log('error.status: ', error.status);
          // this.router.navigate(['']);
        } else {
          // Message variable to hold error message
          let errorMessage = '';
          // Variable to hold url location of error
          const url =
            location instanceof PathLocationStrategy ? location.path() : '';
          // server-side error
          errorMessage = this.errorService.getServerMessage(error);
          // get the stack trace, lets grab the last 10 stacks only
          StackTrace.fromError(error).then(stackframes => {
            const stackString = stackframes
              .splice(0, 20)
              .map(function(sf) {
                return sf.toString();
              })
              .join();
            /**
             * Function to log errors to api and mantis
             *
             * @param (errorMessage) error message passed to function
             * @param (url) url passed to function
             * @param (stackString) stackString passed to function
             */
            this.logger
              .createErrorLog(errorMessage, url, stackString)
              .subscribe(
                result => {
                  console.log('log filed: ', result);
                },
                (err: any) => console.log(err)
              );
          });
          // Check if error is undefined and open dialog with appropriate error info
          if (typeof errorMessage !== 'undefined') {
            this.openDialog(errorMessage);
          } else {
            this.openDialog('undefined');
          }
          // throw error
          return throwError(errorMessage);
        }
      })
    );
  }
  /**
   * Function to open dialog to display error
   *
   * @param (data) error data to display
   */
  openDialog(data): void {
    // Constant to hold and call dialog to display error
    const dialogRef = this.dialog.open(ErrorDialogComponent, {
      width: '60%',
      data: data
    });
    // Code to run after the dialog is closed
    dialogRef.afterClosed().subscribe(result => {
      // Redirect back to home (dashboard)?
    });
  }
}

如您所见,我有一个简单的 if 我在哪里检查状态码。然后我有一个导航方法调用,我试图路由到任何内容,因为我的路由器模块有未找到的组件列为“无”路由。

这是重定向,但也显示错误对话框消息。我不希望这样显示。该对话框仅向最终用户显示错误消息,并为他们提供联系我们的方式。

这是我的全局处理程序...
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import {
  HttpErrorResponse,
  HttpHeaders,
  HttpClient
} from '@angular/common/http';
import { LocationStrategy, PathLocationStrategy } from '@angular/common';
import { throwError } from 'rxjs';
import * as StackTrace from 'stacktrace-js';
import { LoggerService } from '../core/logger.service';
import { ErrorService } from '../core/error.service';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';
import { ConfigService } from '../app-config.service';

@Injectable({
  providedIn: 'root'
})
/**
 * GlobalErrorHandler to grab errors and log them
 */
export class GlobalErrorHandler implements ErrorHandler {
  /**
   * constructor to inject
   */
  constructor(private injector: Injector, public dialog: MatDialog) {}
  /**
   * Function to handle errors
   *
   * @param (error) error passed to function
   */
  handleError(error: Error) {
    console.log('error (global): ', error);
    const errorService = this.injector.get(ErrorService);
    const logger = this.injector.get(LoggerService);
    const location = this.injector.get(LocationStrategy);
        // Message variable to hold error message
    let errorMessage;
    // Variable to hold url location of error
    const url = location instanceof PathLocationStrategy ? location.path() : '';
    console.log('url: ', url);
    // check if error is a client error
    if (error instanceof Error) {
      // Client error message from error service
      errorMessage = errorService.getClientMessage(error);
      // Open dialog and display error message
      this.openDialog(errorMessage);
    }
    // get the stack trace, lets grab the last 10 stacks only
    StackTrace.fromError(error).then(stackframes => {
      const stackString = stackframes
        .splice(0, 20)
        .map(function(sf) {
          return sf.toString();
        })
        .join();
      /**
       * Function to log errors to api and mantis
       *
       * @param (errorMessage) error message passed to function
       * @param (url) url passed to function
       * @param (stackString) stackString passed to function
       */
      logger.createErrorLog(errorMessage, url, stackString).subscribe(
        result => {
          console.log('log filed');
        },
        (err: any) => console.log(err)
      );
    });
    return throwError(error);
  }
  /**
   * Function to open dialog to display error
   *
   * @param (data) error data to display
   */
  openDialog(data): void {
    const dialogRef = this.dialog.open(ErrorDialogComponent, {
      width: '60%',
      data: data
    });
    // Code to run after the dialog is closed
    dialogRef.afterClosed().subscribe(result => {
      // Redirect back to home (dashboard)?
    });
  }
}

那么有没有办法捕获 404 代码并执行重定向,但不调用全局错误处理程序?

最佳答案

在 Z.Bagley 和他分享的链接的帮助下,我能够修复它。我注意到我错过了 next.handle() 调用。

这是我修改后的拦截器代码...

if (error.status === 404) { 
    const newRequest = request.clone();
    return next.handle(newRequest); 
} 

关于javascript - 根据错误状态代码重定向到 Angular 中的组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60309408/

相关文章:

javascript - 带有 bool 属性的 Angular 指令传递字符串而不是 bool

javascript - 在一个脚本中自动刷新和自动上下滚动

javascript - 如何从外部url加载html源模板

angular - 如何正确捕获@ngrx/effects 错误?

Angular Typescript getter 和 setter 返回未定义

generics - 我可以告诉 TypeScript 泛型类型有构造函数吗?

arrays - 将数组参数直接解压为参数?

javascript - 根据对象属性过滤数组

javascript - 有条件地改变表格数据 Angular 2+ 的颜色

typescript - 构建包时,我的/src文件夹中必须有package.json文件吗?