rest - 自定义 Spring Boot 异常处理以防止在 Rest 响应中返回 Stacktraces

标签 rest spring-boot exception error-handling

如何配置我的 Spring Boot 服务,以便 500 之类的错误不会泄露诸如堆栈跟踪之类的实现细节。

{
  "timestamp": "2019/05/01 15:06:17",
  "status": 500,
  "error": "Internal Server Error",
  "message": "Type definition error: [simple type, class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->........)",
  "path": "/api/test"
}

注:这里的堆栈跟踪位于 message而不是 exception json的一部分。

如您所见,我已经在格式化时间戳:
@Component
public class CustomErrorAttributes extends DefaultErrorAttributes {

  private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
  private static final String TIMESTAMP = "timestamp";

  @Override
  public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

    //Let Spring handle the error first
    Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);

    //Format & update timestamp
    Object timestamp = errorAttributes.get(TIMESTAMP);
    if(timestamp == null) {
      errorAttributes.put(TIMESTAMP, dateFormat.format(new Date()));
    } else {
      errorAttributes.put(TIMESTAMP, dateFormat.format((Date)timestamp));
    }

    return errorAttributes;
  }
}

但我也需要处理消息。

如果这 500 是我能做的唯一错误:
errorAttributes.put("message", "Server error. Contact support.");

但是,所有错误都会在这里发生,这将覆盖所有消息。

我可以检查状态是否为 500,然后才修改它。但是,可能会生成其他错误,这些错误也可能泄漏堆栈跟踪。

使用 @RestControllerAdvice似乎需要知道生成的每个异常并具有 @ExceptionHandler对于每个人,并且知道要响应哪个状态代码。

有没有更清洁的方法来处理这个?

最佳答案

这可能不是“最干净”的方法,但在我参与的项目中,我们对跨项目的错误响应有一个“标准格式”,所以我们有一个自定义对象,其字段与我们的 orgs 标准(HttpStatus、Reason等)扩展了 RuntimeException。然后在我们的 Controller 、服务、存储库等中,我们将捕获异常并相应地创建此对象,然后抛出自定义对象。根据它在应用程序中发生的位置(repo、服务、 Controller 等),我们可以给它自己的自定义措辞,但仍然在我们的服务器日志中注销完整的异常,以便我们稍后进行调查

例如,如果我们在存储库中发现错误,我们将创建自定义错误对象,将原因设置为 DB 不可用(实际上所有消费者都需要知道),将状态设置为 HttpStatus.SERVICE_UNAVAILABLE(我们使用原因和 httpstatus 跟踪这些枚举以保持跨模块的状态相同),并将自定义对象扔到要返回的 Controller 上。

抱歉,如果这是一个冗长的答案,可能无法给你想要的东西,我不太熟悉你是如何尝试这样做的,所以我只想举一个其他方法的例子。我也会放一些示例代码

自定义异常(exception):

data class MyException(
    val reason: String,
    val httpStatus: HttpStatus? = null
) : RuntimeException(reason)

创建方法:
fun createApiException(errorCode: ErrorCodeEnum) = MyException(
    reason = errorCode.reason,
    httpStatus = errorCode.httpStatus,
)

关于rest - 自定义 Spring Boot 异常处理以防止在 Rest 响应中返回 Stacktraces,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55941734/

相关文章:

php - 在 SQL 查询中传递大量值的最佳方法?

java - Sprint TestRestTemplate 返回 Id null

java - 无法使用 spring boot jpa 创建新表

java - Spring Boot自定义查询分组依据和计数

java - 如何修复无法调用元素 RollingFile 类 org.apache.logging.log4j.core.appender.RollingFileAppender 中的工厂方法?

java - Eclipse 警告 Uncaught Error

c++ - 在用户定义的异常析构函数中释放动态内存

apache - CXF 中的 javax.xml.bind.UnmarshalException

exception - grails webflow 中的 BadlyFormattedFlowExecutionKeyException

带有调用过程的 PHP rest API