竹简文档

GlobalErrorController

全局错误控制器,统一处理所有未捕获的异常和 HTTP 错误状态

GlobalErrorController

GlobalErrorController 用于统一处理所有未被 @ExceptionHandler 捕获的异常和 HTTP 错误状态(如 404、500 等)。根据使用的框架不同,实现方式有所差异。

框架实现对比

对比项MVC 版本WebFlux 版本
实现接口ErrorControllerErrorWebExceptionHandler
处理方法返回 ResponseEntity返回 Mono<Void>
请求对象HttpServletRequestServerWebExchange
响应写入框架自动处理手动写入 DataBuffer
自动配置类BaseSdkAutoConfigurationWebFluxSdkAutoConfiguration

工作原理

MVC 版本

HTTP 请求


Spring DispatcherServlet

    ├── 正常处理 → Controller → 返回响应

    └── 异常/错误(未匹配任何 @ExceptionHandler)


        转发至 /error


        GlobalErrorController


        构造 BaseResponse 响应

WebFlux 版本

HTTP 请求


WebFilter Chain

    ├── 正常处理 → Handler → 返回 Mono<Response>

    └── 异常/错误(未匹配任何 @ExceptionHandler)


        GlobalErrorController.handle()


        构造 BaseResponse 并写入响应


        Mono<Void> 完成

错误码映射

GlobalErrorController 将 HTTP 状态码自动映射到对应的 ErrorCode

HTTP 状态码ErrorCode说明
400BAD_REQUEST错误请求
401UNAUTHORIZED未授权
403FORBIDDEN禁止访问
404PAGE_NOT_FOUND页面未找到
405METHOD_NOT_ALLOWED方法不允许
406NOT_ACCEPTABLE不可接受
408TIMEOUT请求超时
429TOO_MANY_REQUESTS请求过多
500SERVER_INTERNAL_ERROR服务器内部错误(仅 WebFlux)
502GATEWAY_ERROR网关错误
503SERVICE_UNAVAILABLE服务不可用
其他SERVER_INTERNAL_ERROR服务器内部错误(仅 MVC)

响应格式

当发生错误时,GlobalErrorController 返回如下格式的响应:

response.json (404 示例)
{
  "context": "550e8400-e29b-41d4-a716-446655440000",
  "output": "PageNotFound",
  "code": 40401,
  "message": "页面未找到",
  "errorMessage": "No static resource found for /api/v1/unknown",
  "duration": 5,
  "data": {
    "path": "/api/v1/unknown",
    "status": 404
  }
}

字段

类型

常见错误场景

404 Not Found

当访问不存在的路径时:

response.json
{
  "context": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
  "output": "PageNotFound",
  "code": 40401,
  "message": "页面未找到",
  "errorMessage": null,
  "duration": 2,
  "data": {
    "path": "/api/v1/users/999",
    "status": 404
  }
}

405 Method Not Allowed

当使用错误的 HTTP 方法时:

response.json
{
  "context": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "output": "MethodNotAllowed",
  "code": 40501,
  "message": "方法不允许",
  "errorMessage": "Request method 'DELETE' not supported",
  "duration": 1,
  "data": {
    "path": "/api/v1/user/profile",
    "status": 405
  }
}

500 Internal Server Error

当发生未捕获的异常时:

response.json
{
  "context": "123e4567-e89b-12d3-a456-426614174000",
  "output": "ServerInternalError",
  "code": 50001,
  "message": "服务器内部错误",
  "errorMessage": "NullPointerException: ...",
  "duration": 150,
  "data": {
    "path": "/api/v1/data/process",
    "status": 500
  }
}

WebFlux 特有功能

处理器结构(仅 WebFlux)

GlobalErrorController.java
public class GlobalErrorController implements ErrorWebExceptionHandler {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Override
    public @NotNull Mono<Void> handle(ServerWebExchange exchange, @NotNull Throwable ex) {
        // 确定状态码
        HttpStatus status = this.determineHttpStatus(ex);
        String requestPath = exchange.getRequest().getPath().value();

        // 映射状态码到 ErrorCode
        ErrorCode errorCode = this.mapStatusCodeToErrorCode(status.value());

        // 构建错误详情
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("path", requestPath);
        errorDetails.put("status", status.value());

        // 使用 ResultUtil 构造响应并写入
        return ResultUtil.error(errorCode, errorMessage, errorDetails)
                .flatMap(response -> this.writeResponse(exchange, response));
    }
}

特殊异常处理(仅 WebFlux)

ResponseStatusException

WebFlux 中常见的 ResponseStatusException 会被正确处理:

示例
// 在 Handler 中抛出
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");

// GlobalErrorController 会提取状态码 404,映射到 PAGE_NOT_FOUND

IllegalArgumentException

对于 IllegalArgumentException,返回 400 状态码:

GlobalErrorController.java
private HttpStatus determineHttpStatus(Throwable ex) {
    if (ex instanceof ResponseStatusException rse) {
        return HttpStatus.valueOf(rse.getStatusCode().value());
    }
    if (ex instanceof IllegalArgumentException) {
        return HttpStatus.BAD_REQUEST;
    }
    return HttpStatus.INTERNAL_SERVER_ERROR;
}

响应写入机制(仅 WebFlux)

WebFlux 版本需要手动将响应写入 ServerHttpResponse

GlobalErrorController.java
private Mono<Void> writeResponse(
        ServerWebExchange exchange,
        ResponseEntity<BaseResponse<Map<String, Object>>> response
) {
    ServerHttpResponse serverResponse = exchange.getResponse();

    // 设置状态码
    serverResponse.setStatusCode(response.getStatusCode());

    // 设置内容类型
    serverResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);

    // 序列化响应体
    try {
        String jsonBody = OBJECT_MAPPER.writeValueAsString(response.getBody());
        DataBuffer buffer = serverResponse.bufferFactory()
                .wrap(jsonBody.getBytes(StandardCharsets.UTF_8));
        return serverResponse.writeWith(Mono.just(buffer));
    } catch (JsonProcessingException e) {
        // 序列化失败时的降级处理
        String fallbackBody = "{\"output\":\"UnknownError\",\"code\":50999}";
        DataBuffer buffer = serverResponse.bufferFactory()
                .wrap(fallbackBody.getBytes(StandardCharsets.UTF_8));
        return serverResponse.writeWith(Mono.just(buffer));
    }
}

MVC 特有功能

自定义错误路径(仅 MVC)

默认错误路径为 /error,可通过配置修改:

application.yml
server:
  error:
    path: /custom-error

生产环境配置(仅 MVC)

生产环境建议关闭详细的错误信息输出:

application.yml
server:
  error:
    include-message: never

与异常处理器的关系

GlobalErrorController 是异常处理的最后一道防线:

异常抛出


@ExceptionHandler 匹配?

    ├── 是 → 对应的 ExceptionHandler 处理

    └── 否 → Spring 转发至 /error(MVC)或传播至 ErrorWebExceptionHandler(WebFlux)


            GlobalErrorController 处理

注意事项

  • GlobalErrorController 由对应的自动配置类自动注册,无需手动声明
  • 该控制器仅处理未被 @ExceptionHandler 捕获的错误
  • 响应格式与 ResultUtil.error() 保持一致,确保前端处理逻辑统一
  • WebFlux 版本在序列化失败时会返回降级响应,避免级联错误

下一步

On this page