对正常的应用程序流程使用 500 响应代码是否可行?使用 Angular7+Spring 设计弹出消息

Is using 500 response code for normal app flow viable? Designing popup messages with Angular7+Spring

从 Java 的角度来看,使用异常来处理预期结果是错误的(异常应该是它们的名称)。

对于我所有的服务,我创建了包装器机制,如果发生这种情况,它基本上会提供有关失败的详细信息(所有 return 都是任意的 Result<?>)。现在我需要在客户端浏览器的一些弹出窗口中显示此消息。

在 Angular 中有 HttpClient 实际上支持捕获 http 响应错误: https://angular.io/guide/http#error-handling

这是从服务器向客户端报告错误的可行方式吗?

在 Angular 中有没有一种方法可以定义一些提取器来拆分来自后端的响应 API?

说我会让我的整个休息 API return 身体:

{
    messageType: "", // Success, Failure, Warning
    message: "Message",
    content: {
        ...
    }
}

这样我就可以在拦截器中删除 message, messageType,在弹出窗口中显示它们,然后仅将 content 进一步传递为 body?

一种使用@ControllerAdvice 捕获服务端所有异常的好方法,并在标准结构中抛出具有预期异常消息和状态代码的user/feature 特定异常,以便前端可以有一个异常控制器来评估此异常消息在动态弹出消息中动态显示到来自服务的任何消息。

既然我是从纯粹的 Java 后端进入网络的——JAVA 中的异常是不好的(一般来说),为什么在使用 HTTP 时遵循同样的错误做法(使用错误作为信息)? 经过更多阅读后,我可以说 - 不要这样做,除非它实际上是一个错误,例如:

  • 404 如果客户端尝试访问 ID 不存在的实体。
  • 500 当服务器实际上无法处理某事时(实际异常)。

这是我的 Result<?> 系统的 Angular 部分。

拦截器:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse } from '@angular/common/http';

import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { Globals } from '../globals.service';

@Injectable()
export class PopupInterceptor implements HttpInterceptor {

    constructor(private globals: Globals) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.url.startsWith(this.globals.apiHost)) {
            return next.handle(req)
                .pipe(
                    map(e => {
                        if (e instanceof HttpResponse) {
                            const response = <Response>e.body;
                            // use response to do whatever - I am injecting popup service and pushing response.message there for display in component.
                            return e.clone({ body: response.result });
                        }
                    })
                );
        }
        return next.handle(req);
    }
}

interface Response {
    type: string;
    message: string;
    result: any;
}

globals.service:

import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
})
export class Globals {
    apiHost = '/api/';
}

app.module:

providers: [
        { provide: HTTP_INTERCEPTORS, useClass: PopupInterceptor, multi: true }
    ],