Java开发规范(五)| 接口设计规范---前后端/跨服务协作的"架构级契约"
- 前言
- 一、为什么架构设计阶段必须定接口契约?
- 二、RESTful语义规范【强制】:架构级资源定义
-
- [1. 资源与HTTP方法的架构映射](#1. 资源与HTTP方法的架构映射)
- [2. URL架构设计:层级清晰,无动词,可扩展](#2. URL架构设计:层级清晰,无动词,可扩展)
- [3. 分页参数+DTO标准化(架构级落地)](#3. 分页参数+DTO标准化(架构级落地))
- [4. 版本控制:架构级兼容设计](#4. 版本控制:架构级兼容设计)
- 三、请求/响应规范【强制】:架构级标准化格式
-
- [1. 请求规范:校验前置,格式统一](#1. 请求规范:校验前置,格式统一)
- [2. 响应规范:全局统一,异常码分层](#2. 响应规范:全局统一,异常码分层)
-
- (1)统一响应体:`code+msg+data+timestamp`四段式
- (2)异常码体系:架构级分层定义
- (3)响应示例(成功/失败)
- (4)响应避坑:禁止敏感数据、冗余字段
- (5)HTTP状态码与业务码的协同设计
-
- [① 核心分工原则](#① 核心分工原则)
- [② ResponseEntity的使用场景](#② ResponseEntity的使用场景)
- [③ 编码示例(两种写法对比)](#③ 编码示例(两种写法对比))
- [④ JSON字段名统一转换(前后端协作核心)](#④ JSON字段名统一转换(前后端协作核心))
- [⑤ 架构级约束(强制)](#⑤ 架构级约束(强制))
- 四、API文档规范【强制】:架构级契约自动化
-
- [1. 工具选型:SpringDoc-OpenAPI(适配Spring Boot 2.7+)](#1. 工具选型:SpringDoc-OpenAPI(适配Spring Boot 2.7+))
- [2. 文档契约必备信息(架构级要求)](#2. 文档契约必备信息(架构级要求))
- [3. 带契约注解的Controller示例](#3. 带契约注解的Controller示例)
- [4. 文档访问与环境管控](#4. 文档访问与环境管控)
- 五、兼容性规范【强制】:架构级迭代保障
-
- [1. 向后兼容三大原则](#1. 向后兼容三大原则)
- [2. 接口废弃流程(架构级)](#2. 接口废弃流程(架构级))
- 六、云原生适配规范【新增】:架构级接口暴露
-
- [1. API网关集成(统一入口)](#1. API网关集成(统一入口))
- [2. 服务网格(Istio)适配](#2. 服务网格(Istio)适配)
- [3. K8s部署适配](#3. K8s部署适配)
- 七、安全与性能规范【强制】:架构级防护
-
- [1. 安全规范](#1. 安全规范)
- [2. 性能规范](#2. 性能规范)
- [3. 幂等性实战(Redis去重)](#3. 幂等性实战(Redis去重))
- 八、工具支持与落地流程(架构级保障)
-
- [1. 工具链选型(大厂标配)](#1. 工具链选型(大厂标配))
- [2. 落地流程(架构→编码→测试→上线)](#2. 落地流程(架构→编码→测试→上线))
- 九、常见反模式与落地Checklist
-
- [1. 常见反模式(自查)](#1. 常见反模式(自查))
- [2. 落地Checklist(架构阶段必完成)](#2. 落地Checklist(架构阶段必完成))
- 十、总结:接口契约是协作的"第一生产力"
前言
接口是架构设计的"对外契约"------前端与后端、服务与服务的协作,本质是对接口契约的遵守。若接口设计缺乏标准化,会导致"协作成本爆炸":
- 前端反复适配不同格式响应(一会儿
success: true,一会儿code: 200); - 跨服务调用因无版本、无文档,调用一次报一次错;
- 迭代时接口变更直接引发依赖方故障,回滚成本极高。
大厂接口设计的核心是 "架构阶段定契约,编码阶段守契约,迭代阶段兼容契约"------接口不仅是数据传输通道,更是"跨角色、跨团队的通用语言"。本文基于架构视角,补充云原生适配、契约测试、字段名转换配置等实战内容,让规范从"纸面规则"落地为"可自动化校验、可全流程管控"的协作标准。
一、为什么架构设计阶段必须定接口契约?
接口契约的缺失,会导致后期协作和迭代成本呈指数级上升。
反面案例:架构缺失契约引发"全链路故障"
- 背景 :某电商平台未明确接口契约:① 订单与支付服务的"支付回调接口"仅口头约定参数;② 订单服务迭代时,新增
tradeNo未设默认值,且删除旧字段outTradeNo;③ 无版本控制,URL仍为/api/order/pay/callback。 - 后果 :支付回调因
outTradeNo缺失解析失败,导致"支付成功但订单未更新";tradeNo无默认值引发旧版本序列化报错,全链路阻塞2小时,损失超300万。 - 规范价值:架构阶段明确"契约文档+版本控制+兼容性规则",可完全规避此类故障------契约是协作基石。
接口设计的4个核心价值(架构视角)
- 降协作成本:统一契约让前后端/跨服务无需反复沟通,"按契约开发、按契约测试";
- 减迭代风险:兼容性规则保障迭代不影响旧依赖方,支持"平滑升级";
- 提可扩展性:标准化接口便于接入API网关、服务网格,适配云原生;
- 简问题定位:统一响应格式、异常码,快速区分"客户端/服务端/网络问题"。
二、RESTful语义规范【强制】:架构级资源定义
RESTful的核心是"用HTTP方法表语义,用URL表资源",架构阶段需明确资源定义与HTTP方法映射,避免编码随意性。
1. 资源与HTTP方法的架构映射
| 资源操作 | HTTP方法 | 幂等性 | 架构设计要点 | 示例URL |
|---|---|---|---|---|
| 查询单个资源 | GET | 是 | 路径参数为资源唯一ID,返回单个DTO | GET /api/v1/orders/1001 |
| 查询资源列表 | GET | 是 | 支持过滤、排序、分页,参数放QueryString | GET /api/v1/orders?status=1&pageNum=1&pageSize=10 |
| 创建资源 | POST | 否 | 请求体为创建DTO,返回资源ID/完整资源 | POST /api/v1/orders |
| 全量更新资源(覆盖) | PUT | 是 | 需传入完整字段,缺失字段设默认值 | PUT /api/v1/users/2001 |
| 部分更新资源(增量) | PATCH | 是 | 请求体仅传需更新字段,用JSON Patch格式 | PATCH /api/v1/orders/1001 |
| 删除资源 | DELETE | 是 | 路径参数为资源唯一ID,返回成功标识 | DELETE /api/v1/orders/1001 |
- 架构级约束 :
- 禁止用GET做写操作(如
GET /api/v1/orders/delete?id=1001):GET会被缓存,导致重复执行; - 禁止用POST替代所有操作(如
POST /api/v1/getOrder):语义混乱,无法利用HTTP幂等性; - 幂等接口必须支持重试:PUT/DELETE/GET需保证"多次调用结果一致",便于网关自动重试。
- 禁止用GET做写操作(如
2. URL架构设计:层级清晰,无动词,可扩展
- 规则1 :URL用"名词复数"表资源集合,禁止含动词(
get/delete/update);- 正确:
/api/v1/users(用户集合)、/api/v1/orders/1001/items(订单子资源); - 错误:
/api/v1/getUser、/api/v1/orderList。
- 正确:
- 规则2 :URL层级不超过3层,避免维护成本高;
- 错误:
/api/v1/users/2001/orders/1001/items/3001; - 优化:
/api/v1/order-items/3001(子资源独立URL,通过orderId关联)。
- 错误:
- 规则3 :过滤/排序/分页参数标准化;
- 过滤:
status=1(等于)、createTimeStart=2024-11-01(范围); - 排序:
sort=createTime,desc(字段+方向,默认升序); - 分页:
pageNum=1(当前页,默认1)、pageSize=10(每页条数,默认10,最大100); - 示例:
/api/v1/orders?status=1&createTimeStart=2024-11-01&sort=createTime,desc&pageNum=1&pageSize=20。
- 过滤:
3. 分页参数+DTO标准化(架构级落地)
分页是高频场景,需统一参数命名与DTO结构,避免协作混乱。
(1)分页DTO全局定义(泛型复用)
java
@Data
@Schema(description = "分页响应通用结构")
public class PageInfo<T> {
@Schema(description = "当前页", example = "1")
private Integer currentPage;
@Schema(description = "总页数", example = "5")
private Integer totalPages;
@Schema(description = "每页条数", example = "10")
private Integer pageSize;
@Schema(description = "总条数", example = "48")
private Long totalCount;
@Schema(description = "分页数据列表")
private List<T> list;
// 可选扩展:前端友好字段
@Schema(description = "是否有下一页", example = "true")
private Boolean hasNextPage;
}
(2)分页接口示例(URL+响应)
-
URL:
/api/v1/orders?status=1&sort=createTime,desc&pageNum=1&pageSize=20 -
响应体:
json{ "code": 200, "msg": "成功", "data": { "current_page": 1, "total_pages": 5, "page_size": 20, "total_count": 48, "list": [/* 订单数据 */], "has_next_page": true }, "timestamp": 1732867200000 }
4. 版本控制:架构级兼容设计
- 规则 :版本号用
v+数字嵌入URL路径(最直观),禁止无版本或HTTP头带版本;- 正确:
/api/v1/orders(v1稳定版)、/api/v2/orders(v2迭代版,兼容v1); - 错误:
/api/orders(无版本)、X-API-Version: 1(HTTP头带版本,难调试)。
- 正确:
- 兼容原则 :
- 主版本(v1→v2):允许不兼容变更,但保留旧版本至少6个月;
- 次版本(v1.1→v1.2):仅允许兼容变更(新增字段、优化逻辑),禁止删字段/改语义。
三、请求/响应规范【强制】:架构级标准化格式
统一请求/响应格式是降协作成本的核心,架构阶段需定义全局DTO与异常码体系。
1. 请求规范:校验前置,格式统一
(1)参数校验:全局拦截,避免重复编码
-
规则:所有参数(路径/Query/请求体)通过JSR303注解校验,全局异常拦截器统一处理,禁止Service层处理校验。
-
全局异常拦截器实现 :
java@RestControllerAdvice public class GlobalExceptionHandler { // 拦截请求体参数校验异常 @ExceptionHandler(MethodArgumentNotValidException.class) public Result<?> handleValidationException(MethodArgumentNotValidException e) { String errorMsg = e.getBindingResult().getFieldErrors().stream() .map(fieldError -> fieldError.getField() + ":" + fieldError.getDefaultMessage()) .collect(Collectors.joining(",")); return Result.fail(400, "参数校验失败:" + errorMsg); } // 拦截路径/Query参数校验异常 @ExceptionHandler(ConstraintViolationException.class) public Result<?> handleConstraintViolationException(ConstraintViolationException e) { String errorMsg = e.getConstraintViolations().stream() .map(violation -> violation.getPropertyPath() + ":" + violation.getMessage()) .collect(Collectors.joining(",")); return Result.fail(400, "参数校验失败:" + errorMsg); } } -
请求DTO示例(带JSR303注解) :
java@Data @Schema(description = "订单创建请求参数") public class OrderCreateRequest { @NotNull(message = "用户ID不能为空") @Schema(description = "用户ID", example = "2001", required = true) private Long userId; @NotEmpty(message = "商品列表不能为空") @Schema(description = "商品列表", required = true) private List<GoodsDTO> goodsList; @NotNull(message = "订单金额不能为空") @Min(value = 0, inclusive = false, message = "订单金额必须大于0") @Schema(description = "订单金额", example = "299.00", required = true) private BigDecimal amount; @Data @Schema(description = "商品子参数") public static class GoodsDTO { @NotNull(message = "商品ID不能为空") @Schema(description = "商品ID", example = "3001", required = true) private Long goodsId; @Min(value = 1, message = "购买数量至少为1") @Schema(description = "购买数量", example = "2", required = true) private Integer quantity; } }
(2)请求体格式:JSON为主,禁止复杂嵌套
- 规则 :POST/PUT/PATCH请求体必须用JSON(
Content-Type: application/json),嵌套层级≤2层;-
错误示例(嵌套过深):
json{ "user": { "profile": { "address": { "province": "北京", "city": "北京" } } } } -
优化示例(扁平/子DTO):
json{ "userId": 2001, "address": { "province": "北京", "city": "北京" } }
-
2. 响应规范:全局统一,异常码分层
(1)统一响应体:code+msg+data+timestamp四段式
-
全局响应DTO定义 :
java@Data @NoArgsConstructor @AllArgsConstructor public class Result<T> { /** 业务状态码:200=成功,4xx=客户端错,5xx=服务端错,5xxx=业务错 */ @Schema(description = "业务状态码", example = "200") private int code; /** 提示消息 */ @Schema(description = "提示消息", example = "成功") private String msg; /** 响应数据 */ @Schema(description = "响应数据") private T data; /** 响应时间戳(毫秒) */ @Schema(description = "响应时间戳", example = "1732867200000") private long timestamp; // 静态工厂方法 public static <T> Result<T> success(T data) { return new Result<>(200, "成功", data, System.currentTimeMillis()); } public static Result<?> fail(int code, String msg) { return new Result<>(code, msg, null, System.currentTimeMillis()); } }
(2)异常码体系:架构级分层定义
| 码段范围 | 含义 | 核心场景 | 示例 |
|---|---|---|---|
| 2xx | 成功 | 通用成功 | 200=成功 |
| 4xx | 客户端错误 | 参数错、未登录、无权限、资源不存在 | 400=参数错,401=未登录,403=无权限 |
| 5xx | 服务端错误 | 通用服务错、未实现、服务不可用 | 500=服务错,503=服务不可用 |
| 5001-5999 | 业务错误(用户模块) | 用户不存在、余额不足 | 5001=用户不存在 |
| 6001-6999 | 业务错误(订单模块) | 订单不存在、已支付、库存不足 | 6001=订单不存在 |
- 规则:异常码需在架构阶段统一注册(如Confluence/配置中心),禁止开发人员随意定义。
(3)响应示例(成功/失败)
-
成功响应(查询订单):
json{ "code": 200, "msg": "成功", "data": { "orderId": 1001, "userId": 2001, "amount": 299.00, "status": 1, "createTime": "2024-11-29 15:30:00" }, "timestamp": 1732867200000 } -
失败响应(业务错误):
json{ "code": 6002, "msg": "订单已支付,无法取消", "data": null, "timestamp": 1732867201000 }
(4)响应避坑:禁止敏感数据、冗余字段
- 敏感数据过滤:用
@JsonIgnore过滤密码、身份证号(如用户DTO忽略password); - 冗余字段剔除:禁止返回
isSuccess: true(可通过code=200判断); null字段处理:配置spring.jackson.default-property-inclusion=non_null,省略null字段。
(5)HTTP状态码与业务码的协同设计
HTTP状态码(传输层)与业务code(业务层)需分工明确,避免混乱。
① 核心分工原则
| 状态码类型 | 作用域 | 决策方 | 示例场景 |
|---|---|---|---|
| 业务code | 业务逻辑层(前后端) | 架构师+业务负责人 | 200=业务成功,6001=订单不存在 |
| HTTP状态码 | HTTP传输层(网关/浏览器) | 架构师+后端开发 | 200=请求成功,400=参数错,404=资源不存在 |
② ResponseEntity的使用场景
| 接口场景 | 是否用ResponseEntity | 示例 |
|---|---|---|
| 对外接口(C端/B端/第三方) | 是 | 参数错返回ResponseEntity.badRequest().body(Result.fail(400, "参数错")) |
| 内部微服务接口 | 否 | 直接返回Result.ok(data)(HTTP默认200) |
| 特殊响应(文件下载/跨域) | 是 | 导出文件:ResponseEntity.ok().header("Content-Disposition", "attachment;filename=order.xlsx").body(fileStream) |
③ 编码示例(两种写法对比)
-
写法1:对外接口(用ResponseEntity)
java@GetMapping("/api/v1/orders/page") public ResponseEntity<Result<PageInfo<OrderDTO>>> pageOrders( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { if (pageNum < 1) { return ResponseEntity.badRequest().body(Result.fail(400, "页码不能小于1")); } PageInfo<OrderDTO> pageData = orderService.pageOrders(pageNum, pageSize); return ResponseEntity.ok(Result.success(pageData)); } -
写法2:内部接口(直接返回Result)
java@GetMapping("/api/v1/orders/page") public Result<PageInfo<OrderDTO>> pageOrders( @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { if (pageNum < 1) { return Result.fail(400, "页码不能小于1"); } PageInfo<OrderDTO> pageData = orderService.pageOrders(pageNum, pageSize); return Result.success(pageData); }
④ JSON字段名统一转换(前后端协作核心)
前后端字段名风格统一是协作关键,大厂约定"后端小驼峰→前端下划线",通过Jackson自动转换:
-
架构级配置(Spring Boot) :
yamlspring: jackson: # 核心:Java小驼峰 → JSON下划线(currentPage → current_page) property-naming-strategy: SNAKE_CASE # 可选:省略null字段,减前端判断成本 default-property-inclusion: non_null -
前后端字段对应示例 :
后端Java字段(小驼峰) JSON字段(下划线) 前端接收字段 约束 currentPage current_page current_page 前端必须按下划线取值 orderPayStatus order_pay_status order_pay_status 禁止手动拼接JSON字段名 -
特殊场景:纯内部系统可关闭转换(默认不配置),此时后端返小驼峰、前端按小驼峰接收------核心是"全项目统一"。
⑤ 架构级约束(强制)
- 禁止混用ResponseEntity写法:同一项目要么全用,要么全不用;
- 前端判断逻辑:以业务
code为准,HTTP状态码仅用于网关/监控; - 异常拦截适配:全局异常处理器需同步控制HTTP状态码与业务
code。
四、API文档规范【强制】:架构级契约自动化
API文档是契约的"载体",大厂要求"实时同步代码、信息完备、可调试、可自动化校验"。
1. 工具选型:SpringDoc-OpenAPI(适配Spring Boot 2.7+)
-
替代Springfox-Swagger2:支持OpenAPI 3.0,自动同步代码注解。
-
集成配置 :
xml<!-- pom.xml依赖 --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.2.0</version> </dependency>java@Configuration public class OpenApiConfig { @Bean public OpenAPI mallOpenAPI() { return new OpenAPI() .info(new Info() .title("商城系统API契约文档") .version("v1.0.0") .description("前后端/跨服务协作契约,接口变更需同步更新文档") .contact(new Contact().name("技术团队").email("tech@mall.com"))) // 全局Token参数 .components(new Components() .addSecuritySchemes("bearerAuth", new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT"))) // 全局安全要求(所有接口需登录) .addSecurityItem(new SecurityRequirement().addList("bearerAuth")); } }
2. 文档契约必备信息(架构级要求)
- 接口描述:
@Tag(模块)、@Operation(功能+场景); - 参数描述:
@Schema(含义+示例+是否必填)、@Parameter(路径/Query参数); - 响应描述:
@ApiResponses(成功/失败示例+异常码说明); - 权限要求:是否需登录、角色(如
@PreAuthorize("hasRole('ADMIN')")); - 兼容性说明:是否兼容旧版本、废弃字段说明。
3. 带契约注解的Controller示例
java
@RestController
@RequestMapping("/api/v1/orders")
@Tag(name = "订单接口(v1)", description = "订单CRUD,兼容v1.0所有功能")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
@Operation(
summary = "创建订单",
description = "用户下单核心接口,需传用户ID、商品列表、金额;幂等性:通过X-Request-Id去重",
requestBody = @RequestBody(
description = "订单创建参数",
required = true,
content = @Content(schema = @Schema(implementation = OrderCreateRequest.class))
)
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "创建成功", content = @Content(schema = @Schema(implementation = Result.class))),
@ApiResponse(responseCode = "400", description = "参数错(如金额≤0)", content = @Content(schema = @Schema(implementation = Result.class))),
@ApiResponse(responseCode = "6002", description = "库存不足", content = @Content(schema = @Schema(implementation = Result.class)))
})
public Result<Long> createOrder(
@RequestHeader(value = "X-Request-Id", required = true) String requestId,
@Valid @RequestBody OrderCreateRequest request
) {
Long orderId = orderService.createOrder(requestId, request);
return Result.success(orderId);
}
@GetMapping("/{orderId}")
@Operation(
summary = "查询订单详情",
description = "按订单ID查完整信息,含商品列表、支付状态",
parameters = @Parameter(
name = "orderId",
description = "订单ID(必须>0)",
required = true,
example = "1001",
schema = @Schema(type = "integer")
)
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "查询成功", content = @Content(schema = @Schema(implementation = Result.class))),
@ApiResponse(responseCode = "404", description = "订单不存在", content = @Content(schema = @Schema(implementation = Result.class)))
})
public Result<OrderDetailDTO> getOrderDetail(@PathVariable Long orderId) {
OrderDetailDTO detail = orderService.getOrderDetail(orderId);
return Result.success(detail);
}
}
4. 文档访问与环境管控
-
开发/测试环境:访问
http://localhost:8080/swagger-ui.html,支持在线调试、导出文档; -
预发/生产环境:禁用Swagger UI,仅保留文档导出(供网关/测试工具):
yaml# application-prod.yml springdoc: api-docs: enabled: true path: /api-docs swagger-ui: enabled: false
五、兼容性规范【强制】:架构级迭代保障
接口迭代的核心是"向后兼容",避免引发依赖方故障。
1. 向后兼容三大原则
- 原则1:新增字段必设默认值 :
- 示例:新增
discountAmount(折扣金额),默认值0,旧客户端未解析也不影响; - 实现:DTO用
@DefaultValue("0")或构造函数初始化。
- 示例:新增
- 原则2:不删、不改已有字段 :
- 禁止:v1返
orderId/amount,v2删amount或改status=1语义; - 正确:废弃字段标
@Deprecated、返默认值,3个月后删除;改语义需新增字段(如newStatus)。
- 禁止:v1返
- 原则3:扩展字段用Map兼容未知场景 :
- 示例:订单接口加
extMap(Map<String, Object>),存非核心字段(营销标签),避免频繁加字段。
- 示例:订单接口加
2. 接口废弃流程(架构级)
-
废弃接口示例 :
java@GetMapping("/api/v1/orders/old-query") @Deprecated @Operation( summary = "查询订单(已废弃)", description = "推荐用/api/v1/orders/{orderId},本接口2025-03-01删除" ) public Result<OrderDetailDTO> oldQueryOrder(@RequestParam Long orderId, HttpServletResponse response) { response.setHeader("Deprecation", "true"); response.setHeader("Sunset", "2025-03-01"); // 删除时间 return getOrderDetail(orderId); // 转发到新接口,保证兼容 }
六、云原生适配规范【新增】:架构级接口暴露
云原生环境下,接口需适配API网关、服务网格、K8s部署。
1. API网关集成(统一入口)
-
价值:统一认证、限流、日志,避免直接暴露服务端口。
-
Spring Cloud Gateway配置示例 :
yamlspring: cloud: gateway: routes: - id: order-service-route uri: lb://order-service # 服务名(Nacos/K8s Service) predicates: - Path=/api/v1/orders/** filters: - name: RequestRateLimiter # 限流 args: redis-rate-limiter.replenishRate: 100 # 令牌填充速率 redis-rate-limiter.burstCapacity: 200 # 令牌桶容量 - name: AddResponseHeader # 加版本头 args: name: X-API-Version value: v1
2. 服务网格(Istio)适配
-
要求:接口支持HTTP/1.1,禁止HTTP/2-only特性。
-
Istio VirtualService配置(流量管控) :
yamlapiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: order-service-vs spec: hosts: - order-service http: - match: - uri: prefix: /api/v1/orders route: - destination: host: order-service subset: v1 retries: attempts: 3 # 重试3次 perTryTimeout: 2s # 单次超时2秒 timeout: 5s # 总超时5秒
3. K8s部署适配
-
接口暴露:通过K8s Service(ClusterIP)暴露,外部经Ingress/网关访问,禁止NodePort;
-
健康检查 :实现
/actuator/health(Spring Boot Actuator),供K8s探针检测:yaml# K8s Deployment健康检查 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 60 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 30 periodSeconds: 5
七、安全与性能规范【强制】:架构级防护
1. 安全规范
- 认证授权 :非公开接口需JWT认证,角色权限用
@PreAuthorize控制; - 接口防刷:敏感接口(登录、下单)通过网关限流(Sentinel),结合IP+用户ID双重限流;
- 数据传输:生产环境必用HTTPS,敏感参数(密码、手机号)额外加密(RSA);
- 防注入 :参数禁止直接拼接SQL,用MyBatis
#{}防注入。
2. 性能规范
- 分页必做 :列表查询必须分页,
pageSize最大100,禁止返全量数据; - 缓存优化:高频接口(商品列表、订单查询)加Redis缓存,缓存Key含版本号;
- 异步处理:耗时操作(下单通知、报表生成)用异步线程池,接口立即返回,前端轮询/WebSocket取结果;
- 幂等性设计 :
- POST接口:前端传
X-Request-Id,后端用Redis存requestId去重; - 支付回调:按
outTradeNo去重,避免重复回调。
- POST接口:前端传
3. 幂等性实战(Redis去重)
java
@Service
public class OrderService {
@Autowired
private StringRedisTemplate redisTemplate;
private static final String IDEMPOTENT_KEY = "idempotent:order:";
private static final long EXPIRE = 30L; // 30分钟过期
@Transactional(rollbackFor = Exception.class)
public Long createOrder(String requestId, OrderCreateRequest request) {
// 1. 幂等校验
String key = IDEMPOTENT_KEY + requestId;
Boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, "1", EXPIRE, TimeUnit.MINUTES);
if (Boolean.FALSE.equals(isExist)) {
throw new BusinessException(6003, "请勿重复提交");
}
// 2. 业务逻辑
Long orderId = doCreateOrder(request);
return orderId;
}
}
八、工具支持与落地流程(架构级保障)
1. 工具链选型(大厂标配)
| 工具用途 | 选型 | 价值 |
|---|---|---|
| API文档/契约生成 | SpringDoc-OpenAPI | 自动同步代码,支持OpenAPI 3.0 |
| 参数校验 | Hibernate Validator(JSR303) | 注解式校验,全局拦截统一处理 |
| 契约测试 | Spring Cloud Contract | 自动化校验契约,避适配问题 |
| 接口测试 | RestAssured+Postman | 导入文档自动生成用例 |
| 网关/限流 | Spring Cloud Gateway+Sentinel | 统一入口、限流降级 |
| 监控告警 | Prometheus+Grafana+SkyWalking | 监控QPS、响应时间,设告警 |
2. 落地流程(架构→编码→测试→上线)
- 架构阶段:架构师+前后端+跨服务负责人评审契约,输出《API契约文档》;
- 编码阶段:开发按契约编码,Code Review查RESTful语义、响应格式;
- 测试阶段 :
- 契约测试:Spring Cloud Contract自动校验;
- 性能测试:JMeter压测(目标P99≤500ms);
- 安全测试:扫注入、未授权访问漏洞;
- 上线阶段:网关配置路由、限流,监控接口指标;
- 迭代阶段:变更需重评审契约,同步文档,通知依赖方。
九、常见反模式与落地Checklist
1. 常见反模式(自查)
- URL含动词(如
/api/v1/getOrder); - 用POST替代所有HTTP方法(如
POST /api/v1/queryOrder); - 响应格式不统一(一会儿
success,一会儿code); - 接口无版本,迭代直接改旧接口;
- 新增字段不设默认值,致旧客户端解析失败;
- 列表查询无分页,返全量数据;
- 文档与代码不一致,缺参数/响应说明;
- 敏感接口无防刷,存在安全漏洞;
- POST接口无幂等设计,致重复创建;
- 云原生环境直接暴露服务端口;
- 分页参数命名混乱(
cp/page/currentPage混用); - 对外接口不用ResponseEntity,网关无法识别请求成败;
- 未统一JSON字段名转换,致前端取值失败。
2. 落地Checklist(架构阶段必完成)
| 检查项 | 责任方 | 完成标准 |
|---|---|---|
| 接口契约文档 | 架构师+前后端 | 含参数、响应、示例、兼容性说明 |
| RESTful语义 | 开发负责人 | URL无动词,HTTP方法与操作语义一致 |
| 统一响应格式/异常码 | 架构师 | 全局ResultDTO,异常码分层定义 |
| JSON字段名转换配置 | 开发负责人 | 全局配置Jackson,前后端风格统一 |
| 兼容性规则 | 架构师 | 新增字段设默认值,不删旧字段 |
| 云原生适配 | 架构师+DevOps | 接口经网关暴露,实现健康检查 |
| 安全/性能配置 | 架构师+安全工程师 | 敏感接口限流,高频接口缓存,HTTPS启用 |
| 契约测试/监控 | 测试+运维 | 配置自动化测试,接口QPS/响应时间告警 |
十、总结:接口契约是协作的"第一生产力"
接口设计的本质是"定义协作契约"------好的契约让协作"无需沟通、按规开发",坏的契约则"充满内耗、故障频发"。
大厂的规范不是"编码细节堆砌",而是"架构级协作设计":通过RESTful统一资源操作,通过字段名转换/HTTP状态码协同降前后端适配成本,通过兼容性规则支持平滑迭代,通过云原生适配支撑架构扩展。这些规范看似繁琐,却能避开90%的协作故障。
下一篇《微服务治理规范》,将承接本文契约,解决微服务的注册发现、远程调用、流量治理问题,让分布式协作更高效稳定。