在日常开发中,一个优雅的API,必须提供简单明了的响应值,然后根据状态码就可以大概知道问题的所在。这里主要整理一下HTTP状态码和自定义状态码。
1、HTTP状态码
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含 HTTP 状态码的信息头(server header)用以响应浏览器的请求。
常见的HTTP状态码有:
200-请求成功。
301-资源(网页等)被永久转移到其它URL。
403-服务器拒绝访问。验证身份通过了,但是资源没有权限进行操作。
404-请求资源(网页等)不存在。
500-内部服务器错误。
504-网关超时。服务器作为网关或代理,但是没有及时从上游服务器收到请求。
2、HTTP状态码分类
HTTP状态码可以分为5类:消息响应、成功响应、重定向、客户端错误、服务器错误。
状态 | 描述 |
---|---|
100 | 继续。客户端应继续其请求 |
101 | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议。 |
200 | 请求成功。一般用于GET与POST请求。 |
201 | 已创建。成功请求并创建了新的资源。 |
202 | 已接受。已经接受请求,但未处理完成。 |
203 | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本。 |
204 | 无内容。服务器成功处理,但未返回内容。 |
205 | 重置内容。 |
300 | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择。 |
301 | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替。 |
302 | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI。 |
303 | 查看其它地址。与301类似。使用GET和POST请求查看。 |
304 | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源。 |
305 | 使用代理。所请求的资源必须通过代理访问。 |
400 | 客户端请求的语法错误,服务器无法理解。 |
401 | 用户身份认证失败。 |
402 | 保留,将来使用。 |
403 | 验证身份通过了,但是资源没有权限进行操作。 |
404 | 服务器无法根据客户端的请求找到资源(网页)。 |
405 | 客户端请求中的方法被禁止。 |
500 | 服务器内部错误,无法完成请求。 |
501 | 服务器不支持请求的功能,无法完成请求。 |
502 | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。 |
504 | 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 |
3、自定义响应状态码规范
后端返回给前端一般使用json格式,定义如下:
代码语言:java复制{
#返回状态码
Code:integer,
#返回信息描述
message:string,
#返回值
data:object
}
3.1、返回接口
代码语言:java复制public interface IResultStatus {
/**
* 状态码
* @return
*/
Integer errorCode();
/**
* 异常信息
* @return
*/
String errorMsg();
}
3.2、状态码枚举:
代码语言:java复制public enum ResultStatus implements IResultStatus {
/**
* 状态码及对应信息
*/
//成功状态码
SUCCESS(0, "执行成功"),
//参数错误:1001~1999
PARAM_IS_INVALID(1001, "参数无效"),
PARAM_IS_BLANK(1002, "参数为空"),
PARAM_TYPE_BIND_ERROR(1003, "参数类型错误"),
//用户错误:2001~2999
USER_LOGIN_ERROR(2001, "账号不存在或密码错误"),
USER_ACCOUNT_FORBIDDEN(2002, "账户已被禁用"),
USER_NOT_EXIST(2003, "用户不存在");
private int errorCode;
private String errorMsg;
ResultStatus(int errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
@Override
public Integer errorCode() {
return errorCode;
}
@Override
public String errorMsg() {
return errorMsg;
}
}
状态码和信息就会一一对应,比较好维护。这样前端同事在得到返回值后,根据状态码就可以知道,大概是什么错误,再根据message相关的信息描述,可以快速定位。
3.3、返回数据体
json格式,根据不同的业务有不同的json体,可以设计一个返回体类Result
代码语言:java复制@Data
public class Result<T> {
private Integer code;
private String message;
private Object data;
public Result(ResultStatus restStatus, Object data) {
this.code = restStatus.errorCode();
this.message = restStatus.errorMsg();
this.data = data;
}
/**
* 业务成功返回业务代码和描述信息
*/
public static Result<Void> success() {
return new Result<Void>(ResultStatus.SUCCESS, null);
}
/**
* 业务成功返回业务代码,描述和返回的参数
*/
public static <T> Result<T> success(T data) {
return new Result<T>(ResultStatus.SUCCESS, data);
}
/**
* 业务成功返回业务代码,描述和返回的参数
*/
public static <T> Result<T> success(ResultStatus resultStatus, T data) {
if (resultStatus == null) {
return success(data);
}
return new Result<T>(resultStatus, data);
}
/**
* 业务异常返回业务代码和描述信息
*/
public static <T> Result<T> failure() {
return new Result<T>(ResultStatus.PARAM_TYPE_BIND_ERROR, null);
}
/**
* 业务异常返回业务代码,描述和返回的参数
*/
public static <T> Result<T> failure(ResultStatus resultStatus) {
return failure(resultStatus, null);
}
/**
* 业务异常返回业务代码,描述和返回的参数
*/
public static <T> Result<T> failure(ResultStatus resultStatus, T data) {
if (resultStatus == null) {
return new Result<T>(ResultStatus.PARAM_IS_INVALID, null);
}
return new Result<T>(resultStatus, data);
}
}
3.4、返回体测试
代码语言:java复制@RestController
@RequestMapping("/api/demo2")
public class Demo2Controller {
private static final HashMap<String, Object> INFO;
static {
INFO = new HashMap<>();
INFO.put("name", "张三");
INFO.put("age", "25");
}
@GetMapping("/getInfo")
public Map<String, Object> getInfo() {
return INFO;
}
@GetMapping("/getInfoResult")
public Result<Map<String, Object>> getInfoResult() {
return Result.success(INFO);
}
}
结果参考: