Skip to content

[Feature] Support ProblemDetail (RFC 7807) for Standardized Error Responses #1403

@CrazyHZM

Description

@CrazyHZM

中文描述

特性概述

移植 Spring Framework 6.0+ / Spring Boot 3.0+ 的 ProblemDetail (RFC 7807) 支持到 SOFABoot,用于标准化 REST API 错误响应。

来源

对 SOFABoot 的价值

  1. 标准化错误响应格式: 统一 RPC 和 REST 的错误返回格式,遵循 RFC 7807 标准
  2. 提升可维护性: 使用标准格式便于客户端解析和处理错误
  3. 与 Spring Cloud Gateway 集成: 统一的错误格式便于网关层处理和转换
  4. 丰富错误信息: 支持 typetitlestatusdetailinstance 等字段

实现建议

1. 基础支持

创建 SOFABoot 的 ProblemDetail 支持类:

@RestControllerAdvice
public class SofaProblemDetailExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(SofaBizException.class)
    public ProblemDetail handleSofaBizException(SofaBizException ex, WebRequest request) {
        ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
            HttpStatus.BAD_REQUEST,
            ex.getMessage()
        );
        problemDetail.setType(URI.create("https://sofastack.io/errors/business-exception"));
        problemDetail.setTitle("Business Logic Error");
        problemDetail.setProperty("errorCode", ex.getErrorCode());
        problemDetail.setProperty("service", ex.getServiceName());
        return problemDetail;
    }

    @ExceptionHandler(SofaRpcException.class)
    public ProblemDetail handleSofaRpcException(SofaRpcException ex, WebRequest request) {
        ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
            HttpStatus.SERVICE_UNAVAILABLE,
            "RPC service call failed"
        );
        problemDetail.setType(URI.create("https://sofastack.io/errors/rpc-exception"));
        problemDetail.setTitle("RPC Error");
        problemDetail.setProperty("interfaceId", ex.getInterfaceId());
        problemDetail.setProperty("methodName", ex.getMethodName());
        return problemDetail;
    }
}

2. 配置扩展

@ConfigurationProperties(prefix = "sofa.web.problem-detail")
public class SofaProblemDetailProperties {
    private boolean enabled = true;
    private URI defaultType = URI.create("about:blank");
    private boolean includeStackTrace = false;
    private boolean includeServiceInfo = true;
    // ... getter/setter
}

3. 与 SOFABoot Starter 集成

web-sofa-boot-starterrpc-sofa-boot 中添加自动配置:

@AutoConfiguration
@ConditionalOnWebApplication
@ConditionalOnProperty(prefix = "sofa.web.problem-detail", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SofaProblemDetailProperties.class)
public class SofaProblemDetailAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public SofaProblemDetailExceptionHandler sofaProblemDetailExceptionHandler(
            SofaProblemDetailProperties properties) {
        return new SofaProblemDetailExceptionHandler(properties);
    }
}

可能的挑战

  1. 与现有错误处理兼容: 需要保持与现有 SofaException 处理链的兼容
  2. 序列化格式: 需要考虑与 SOFARPC 的集成,确保跨协议错误传递
  3. 多语言支持: 是否需要支持错误信息的国际化

预期响应示例

{
  "type": "https://sofastack.io/errors/business-exception",
  "title": "Business Logic Error",
  "status": 400,
  "detail": "User account is not active",
  "instance": "/api/v1/users/transfer",
  "errorCode": "USER_NOT_ACTIVE",
  "service": "user-service"
}

相关代码位置

  • sofa-boot-project/sofa-boot-core/rpc-sofa-boot - RPC 异常处理
  • sofa-boot-project/sofa-boot-web - Web 层异常处理 (如果存在)
  • sofa-boot-project/sofa-boot-autoconfigure - 自动配置

Description (English)

Feature Overview

Port ProblemDetail (RFC 7807) support from Spring Framework 6.0+ / Spring Boot 3.0+ to SOFABoot for standardizing REST API error responses.

Source

Value to SOFABoot

  1. Standardized Error Response Format: Unify RPC and REST error return formats following RFC 7807 standard
  2. Improved Maintainability: Standard format facilitates client parsing and error handling
  3. Spring Cloud Gateway Integration: Unified error format facilitates gateway layer processing and transformation
  4. Rich Error Information: Support fields like type, title, status, detail, instance

Implementation Suggestion

1. Basic Support

Create ProblemDetail support classes for SOFABoot:

@RestControllerAdvice
public class SofaProblemDetailExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(SofaBizException.class)
    public ProblemDetail handleSofaBizException(SofaBizException ex, WebRequest request) {
        ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
            HttpStatus.BAD_REQUEST,
            ex.getMessage()
        );
        problemDetail.setType(URI.create("https://sofastack.io/errors/business-exception"));
        problemDetail.setTitle("Business Logic Error");
        problemDetail.setProperty("errorCode", ex.getErrorCode());
        problemDetail.setProperty("service", ex.getServiceName());
        return problemDetail;
    }

    @ExceptionHandler(SofaRpcException.class)
    public ProblemDetail handleSofaRpcException(SofaRpcException ex, WebRequest request) {
        ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
            HttpStatus.SERVICE_UNAVAILABLE,
            "RPC service call failed"
        );
        problemDetail.setType(URI.create("https://sofastack.io/errors/rpc-exception"));
        problemDetail.setTitle("RPC Error");
        problemDetail.setProperty("interfaceId", ex.getInterfaceId());
        problemDetail.setProperty("methodName", ex.getMethodName());
        return problemDetail;
    }
}

2. Configuration Extension

@ConfigurationProperties(prefix = "sofa.web.problem-detail")
public class SofaProblemDetailProperties {
    private boolean enabled = true;
    private URI defaultType = URI.create("about:blank");
    private boolean includeStackTrace = false;
    private boolean includeServiceInfo = true;
    // ... getters/setters
}

3. Integration with SOFABoot Starter

Add auto-configuration in web-sofa-boot-starter or rpc-sofa-boot:

@AutoConfiguration
@ConditionalOnWebApplication
@ConditionalOnProperty(prefix = "sofa.web.problem-detail", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SofaProblemDetailProperties.class)
public class SofaProblemDetailAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public SofaProblemDetailExceptionHandler sofaProblemDetailExceptionHandler(
            SofaProblemDetailProperties properties) {
        return new SofaProblemDetailExceptionHandler(properties);
    }
}

Potential Challenges

  1. Compatibility with Existing Error Handling: Need to maintain compatibility with existing SofaException handling chain
  2. Serialization Format: Need to consider integration with SOFARPC for cross-protocol error transmission
  3. Multi-language Support: Whether to support internationalization of error messages

Expected Response Example

{
  "type": "https://sofastack.io/errors/business-exception",
  "title": "Business Logic Error",
  "status": 400,
  "detail": "User account is not active",
  "instance": "/api/v1/users/transfer",
  "errorCode": "USER_NOT_ACTIVE",
  "service": "user-service"
}

Related Code Locations

  • sofa-boot-project/sofa-boot-core/rpc-sofa-boot - RPC exception handling
  • sofa-boot-project/sofa-boot-web - Web layer exception handling (if exists)
  • sofa-boot-project/sofa-boot-autoconfigure - Auto-configuration

/label ~enhancement ~spring-sync ~web ~rest-api

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions