萧瑟余晖头像
关注

RESTful设计与参数校验详解

RESTful设计与参数校验详解

定位:第 03 篇,讲透 REST 设计规范、版本管理、Bean Validation 校验体系与错误响应标准化
适用版本:Spring Framework 6.x(JDK 17+)


目录


一、REST 设计规范

1.1 核心原则

原则要点
资源化一切皆资源,用名词标识(/orders/{id}),不用动词(避免 /getOrder)
无状态每个请求自带鉴权与上下文,服务端不存会话(利于水平扩展)
统一接口用 HTTP 方法与状态码表达语义,而非自定义动词

1.2 资源命名与集合

复数名词:       /orders、/users
层级表达从属:    /users/{id}/orders(用户的订单)
动作用子资源:    /orders/{id}/refund(POST,动作即资源)
避免:/getUsers、/deleteOrder、URL 里带动词

1.3 状态码规范(必记)

状态码语义
200成功(有响应体)
201创建成功(常带 Location)
204成功、无内容(如删除)
400请求参数错误
401未认证(没登录/凭证无效)
403已认证但无权限
404资源不存在
409冲突(如重复创建)
422语义校验失败
500服务端错误

1.4 查询、分页、过滤

过滤:  /orders?status=PAID&userId=1
分页:  /orders?page=0&size=20
排序:  /orders?sort=createTime,desc

二、版本管理

策略做法特点
URI 版本/v1/orders、/v2/orders直观、易路由,最常用
头版本Accept: application/vnd.api.v2+json更"纯",但不直观
参数版本?version=2少用

兼容性纪律(呼应接口契约):加字段向后兼容;删字段、改类型、改语义必须升版本;旧版本保留过渡期后下线。


三、参数校验

3.1 Bean Validation 注解

public class UserCreateReq {
    @NotBlank(message = "用户名不能为空")
    private String name;

    @Email(message = "邮箱格式错误")
    private String email;

    @Min(value = 0) @Max(value = 150)
    private Integer age;

    @Size(max = 20)
    private String nickname;
}

3.2 触发与失败处理

@PostMapping
User create(@RequestBody @Valid UserCreateReq req) { ... }

@Valid/@Validated 触发校验,失败抛 MethodArgumentNotValidException,交全局异常处理转 400 + 字段级错误信息。

3.3 进阶

特性用法
嵌套校验对象字段上加 @Valid(校验内部对象的约束)
分组校验@Validated(Create.class),注解上标分组
自定义约束自定义注解 + ConstraintValidator(如手机号)
方法级校验类上 @Validated,校验方法参数(配合 AOP)

四、错误响应标准化

4.1 ProblemDetail(RFC 7807,Boot 3 内置)

{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "用户名不能为空",
  "instance": "/users"
}

Boot 3 可开启 spring.mvc.problemdetails.enabled=true 让默认错误走该格式。

4.2 自定义统一错误体

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    ResponseEntity<ApiError> invalid(MethodArgumentNotValidException e) {
        // 提取各字段错误 → 400 + 结构化错误体
    }
    @ExceptionHandler(BizException.class)
    ResponseEntity<ApiError> biz(BizException e) {
        return ResponseEntity.badRequest().body(ApiError.of(e.getCode(), e.getMessage()));
    }
}

要点:业务错误码 + 人类可读消息 + 字段级明细,状态码与错误语义对齐;细节见 04 篇异常体系。


五、总结

  1. REST 规范:资源化名词复数、无状态、HTTP 方法与状态码表达语义;查询/分页/排序走查询参数。
  2. 状态码:201 创建、204 无内容、401 未认证、403 无权限、409 冲突、422 校验失败——与语义对齐而非全 200。
  3. 版本管理:URI 版本最常用;加字段兼容、破坏性变更升版本。
  4. 校验:Bean Validation 注解 + @Valid 触发 + 全局异常转 400;支持嵌套/分组/自定义约束。
  5. 错误标准化:ProblemDetail(RFC 7807)或自定义统一错误体,业务码 + 可读消息 + 字段明细。

六、常见高频面试题

1. 什么是 REST?核心设计原则有哪些?

要点:REST 是以资源为中心的架构风格。原则:资源化(用名词标识资源,如 /orders/{id});统一接口(用 HTTP 方法表达操作、状态码表达结果);无状态(请求自带鉴权,服务端不存会话,利于水平扩展);分层系统与按需代码(可选)。资源用复数名词、层级表达从属,避免动词式 URL。

2. HTTP 方法中哪些是幂等的?为什么重要?

要点:幂等指同一请求执行一次与多次效果相同。GET、PUT、DELETE 幂等;POST、PATCH 非幂等(通常)。重要性:幂等性决定能否安全重试——网络超时后,幂等请求可放心重发,非幂等重试可能重复创建/扣款。这与分布式重试纪律一致(非幂等需幂等键或禁止重试)。

3. 常见状态码的语义?401 和 403 的区别?

要点:200 成功、201 创建成功、204 成功无内容、400 参数错误、404 资源不存在、409 冲突、500 服务端错误。401 未认证——身份凭证缺失或无效(“你是谁不知道”),应引导登录;403 已认证但无权限(“知道你是谁但不能做”)。混用会导致前端无法正确处理(该跳登录还是提示无权限)。

4. Spring 里如何做参数校验?

要点:用 Bean Validation(Jakarta Validation)。入参 DTO 上标约束注解(@NotBlank/@Email/@Min/@Size 等);控制器方法参数上加 @Valid 或 @Validated 触发;校验失败抛 MethodArgumentNotValidException,用 @RestControllerAdvice 全局捕获,转成 400 + 字段级错误信息。支持嵌套校验(字段加 @Valid)、分组校验、自定义约束注解。

5. 如何自定义校验规则(如手机号)?

要点:定义注解(@Phone),用 @Constraint 关联校验器;实现 ConstraintValidator<Phone, String>,在 isValid 写校验逻辑(正则)。注解即可像内置注解一样用在字段上,随 @Valid 触发。适合内置注解无法覆盖的业务规则(手机号、证件号、自定义业务合法性),复用且集中。

6. 为什么推荐统一错误响应格式?

要点:统一错误体(状态码 + 业务错误码 + 可读消息 + 字段明细)让前端/调用方可编程地处理错误(按错误码分支、展示消息),而不是解析各异的堆栈或自由格式;也利于网关聚合与日志关联。实现用 @RestControllerAdvice 全局异常处理器把各类异常映射为统一结构;Boot 3 可直接用 ProblemDetail(RFC 7807)标准。

7. API 版本管理怎么做?

要点:常见三种——URI 版本(/v1/、/v2/,最直观易路由)、请求头版本(Accept 带版本,更纯但不直观)、参数版本(少用)。兼容纪律:加字段向后兼容,删字段/改类型/改语义必须升版本;旧版本保留过渡期并公告下线时间。目标是让演进不破坏存量客户端。

8. 校验失败应该返回什么状态码?

要点:入参格式/约束校验失败通常返回 400(Bad Request)并带字段级错误明细;语义层面的失败(格式对但业务不满足)可用 422(Unprocessable Entity)。关键是响应体包含哪个字段、什么原因,便于客户端修正。不要返回 500(那是服务端问题),也不要 200 包错误码(状态码与语义应对齐)。

9. @Valid 和 @Validated 的区别?

要点:都触发 Bean Validation。@Valid 是 Jakarta 标准注解,支持嵌套校验(在对象字段上标注校验内部对象),可用于字段/参数;@Validated 是 Spring 的扩展,支持分组校验(@Validated(Group.class)),用于类/方法/参数,类上标注还能启用方法级校验(配合 AOP)。日常:参数校验两者皆可,需要分组或方法级校验用 @Validated,需要嵌套用 @Valid。

10. 无状态对设计有什么影响?

要点:服务端不在内存/会话中保存客户端状态,每个请求自带全部所需信息(如 Token)。影响:① 水平扩展容易——请求可打到任意实例,无需会话粘滞;② 鉴权用自包含凭证(JWT)或集中会话存储(Redis);③ 需要上下文的场景显式传递(请求头/参数)。代价是每请求传凭证与可能的重复解析,用缓存缓解。

在这里插入图片描述

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_49076592/article/details/167486948

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--