如何在Angular 7中获取http后端错误响应正文?

时间:2019-06-24 15:19:28

标签: angular angular7 angular-http-interceptors

使用Spring boot作为我的后端,它使用json主体向我的前端angular发送一些错误响应。我有角度的HTTP拦截器设置来拦截HTTP错误。但我无法从后端获取json错误响应。

打开chrome工具,我可以看到响应,当我从角度拦截器记录http错误时,错误对象为null。

return next.handle(request)

      .pipe(tap(event => {
          // 
      }, (err: HttpErrorResponse) => {
        console.log(JSON.stringify(err));
      }));

我希望能够访问从chrome开发工具复制的此响应的message属性

{timestamp: "2019-06-24T15:17:41.864+0000", status: 400, error: "Bad Request",…}
error: "Bad Request"
errors: [{codes: ["Min.examinerLogin.phoneNo", "Min.phoneNo", "Min.java.lang.String", "Min"],…}]
message: "Validation failed for object='examinerLogin'. Error count: 1"
path: "/api/public/letters"
status: 400
timestamp: "2019-06-24T15:17:41.864+0000"
trace: "org.springframework.web.bind.MethodArgumentNotVali"

我的拦截器代码是这样的:

    import {Injectable} from '@angular/core';
import {HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse, HttpResponse} from '@angular/common/http';
import { AuthService } from './auth.service';
import {Router} from '@angular/router';
import {Observable} from 'rxjs';
import {tap} from 'rxjs/operators';
import {MessageService} from 'primeng/api';

@Injectable({
  providedIn: 'root'
})

export class TokenInterceptor implements HttpInterceptor {

  constructor(
    private router: Router,
    private authenticationService: AuthService,
    private messageService: MessageService
    ) {}

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

    return next.handle(request)

      .pipe(tap(event => {
        if (event instanceof HttpResponse) {
          // do stuff with response if you want
        }
      }, (err: HttpErrorResponse) => {
        console.log(JSON.stringify(err));
        if (err instanceof HttpErrorResponse) {

              this.messageService.add({
                severity: 'error',
                summary: 'Server Error', detail: err.error.message
              });
            }
      }));
  }
}

2 个答案:

答案 0 :(得分:0)

请勿尝试将err强制转换为HttpErrorResponse,这只会在这种情况下给您带来麻烦。而是将其强制转换为any。这是更正后的代码:

export class TokenInterceptor implements HttpInterceptor {

  constructor(
    private router: Router,
    private authenticationService: AuthService,
    private messageService: MessageService
    ) {}

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

    return next.handle(request)

      .pipe(tap(event => {
        if (event instanceof HttpResponse) {
          // do stuff with response if you want
        }
      }, (err: any) => {
        console.log(JSON.stringify(err));
        if (err instanceof HttpErrorResponse) {

              this.messageService.add({
                severity: 'error',
                summary: 'Server Error', detail: err.error.message
              });
            }
      }));
  }
}

编辑:

也不要简单地将spring异常错误发送给客户端。客户端一定不知道您正在后端使用Spring。而是使用带有@ExceptionHandler方法的@ControllerAdvice exceptionhandler类发送回自定义错误消息,每个方法处理一个不同的错误。例如,未经身份验证的异常可能由以下方法处理:

@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<String> authenticationException(final AuthenticationException e) {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    return new ResponseEntity<String>("You need to be logged in to do this", headers, HttpStatus.UNAUTHORIZED);
}

这将创建状态代码为401和自定义消息的HttpErrorResponse

编辑2:

关于Spring Boot发送的错误对象的另一条警告。我发现Spring在错误响应中打包错误消息的方式并不十分一致。有时确实可以使用error.error.message来检索错误消息,但有时只能通过从error.error获取错误消息来检索错误消息,在这种情况下,它似乎仍然只具有属性message其值为undefined。为什么这样,我不知道,但是我可以建议所有人在使用消息之前将消息提取到消息变量中,并先进行检查以查看error.error对象是否具有名为message的属性,并且如果是,则检查消息是否未定义。如果不是,请使用message中的值,如果是,请使用error.error中的值。

我知道这听起来很hacky,但这是使这些东西正常工作的唯一方法。实际上,此值是“未定义的”,因此不执行此操作,而在message属性上使用String方法,这是因为spring或angular或决定将消息放入error.error的任何操作都会引起一些怪异的行为。例如,此if(errorMessage && errorMessage.message.includes('#redirect'))导致整个if-else结构被简单破坏,而不是评估条件是真还是假。我通过在if和else括号之间添加console.log(“ test)语句来确认这种奇怪的行为。浏览器中均未显示任何日志,而且我在if-else结构之后放置的任何日志也均未显示!所有这些都是因为我只是简单地对根据角度“未定义”的消息调用.includes,因此不会引发任何JavaScript错误,它只是神秘地且无声地退出if-else结构,而无需经过它们之一,再加上它此后不执行任何日志。我认为这一定是角度错误或其他错误。

无论如何,要说:确定error.error对象是否具有message属性,如果是,请检查angular是否具有未定义的值。您可以使用此代码来检索消息。

let errorMessage:any = (Object.prototype.hasOwnProperty.call(error.error, 'message') && error.error.message != undefined) ? error.error.message : error.error;

答案 1 :(得分:0)

最终使其正常工作...

从这里的答案https://stackoverflow.com/a/48502027/1597923

所以我将此片段添加到了error.interceptor.ts文件中,瞧

....
if (err.error instanceof Blob) {
   const reader: FileReader = new FileReader();
   reader.onloadend = () => {
   if (typeof reader.result === 'string') {
       const err1 = JSON.parse(reader.result);
       this.messageService.add({
          severity: 'error',
          summary: err1.error, detail: err1.message
       });
   }
 };
 reader.readAsText(err.error);
            }
....