使用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
});
}
}));
}
}
答案 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);
}
....