字段描述具体错误,形如:
INVALID_REQUEST
(
"InvalidRequest"
,
"Invalid request, for reason: {0}"
)
错误消息
对于 HTTP 请求而言,正确响应一般都伴随着2xx状态码,以及一个响应消息体。相应地,错误响应也理应有一个错误消息,以便 API 使用者能够知道错误原因,做出修正。当然,错误响应的响应状态码也是必不可少的,且原则上,应该尽可能地返回恰当的 HTTP 状态码,但这并不是我们本文讨论的重点,有兴趣的可以仔细阅读下 RFC 文档。至于错误消息,则没有一个特定的格式。
我们定义错误响应的消息体如下:
{
"requestId"
:
"5f8c89b6-f0d4-48d4-b945-01fbce035c0a"
,
"status"
:
400
,
"reason"
:
"Bad Request"
,
"code"
:
"NotFound"
,
"message"
:
"Resource Book[id=10] not found."
,
"details"
:
"uri=/books/10;client=0:0:0:0:0:0:0:1"
,
"timestamp"
:
"2018-10-16T23:30:40.431+08:00"
}
注:这里只做一个示例,讲述实践方法,具体的错误消息可以根据自己的需要定制。
具体实现
继上述说明,我们接下来用代码说明具体如何实现。该项目为 Maven 多模块项目,文件结构如下

对于一个大中型项目而言,通常我们可以把项目看做一个产品,而产品往往会根据业务分为不同的子模块。对于错误码的定义,通常会分为通用错误码、以及模块内的业务错误码。模拟一个大中型产品,我们这里将项目分为最基本的两个模块,一个代表公用模块,对于通用错误码、通用异常、通用异常处理以及对错误消息通用格式的定义等,我们都会在这个模块中实现。一个模拟的书店模块,依赖前面的公用模块。
为尽量避免通篇大量的代码粘贴,我们在这里只介绍几个重要的文件,具体的实现细节,文章会在最后附上源码地址。
公共模块
公共模块,或者叫通用模块,包括三个重要的子包, constant、 error、 web,我们错误处理实现的主要代码就是在 error 包下。其中:
ErrorCode 是一个接口,作为错误码枚举类型的父接口,其中只有两个方法
public interface ErrorCode {
String getCode ();
String getMessage ();
}
CommonErrorCode 中定义通用错误码,作为产品各个子业务模块的公用部分,如
/**
* 错误请求
*/
INVALID_REQUEST
(
"InvalidRequest"
,
"Invalid request, for reason: {0}"
),
/**
* 参数验证错误
*/
INVALID_ARGUMENT
(
"InvalidArgument"
,
"Validation failed for argument [{0}], hints: {1}"
),
/**
* 未找到资源
*/
NOT_FOUND
(
"NotFound"
,
"Resource {0} not found."
),
/**
* 未知错误
*/
UNKNOWN_ERROR
(
"UnknownError"
,
"Unknown server internal error."
);