微服務間 HTTP 調用,傳統做法在 JSON 體中包裹 status 字段判斷成敗,違背 RESTful 語義。標準 HTTP 狀態碼(200/400/401/404/500...)才是正規溝通協議。
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR, reason = "server error")
public class ServerException extends RuntimeException {}
@GetMapping("/user")
public String getUser(@RequestParam String name) {
if (StringUtils.isEmpty(name)) throw new ServerException();
return "zhangsan";
}
缺點:狀態碼寫死、reason 無法動態、異常類爆炸、無法返回業務數據體。
@GetMapping("/user")
public void getUser(HttpServletResponse response) throws IOException {
response.setStatus(500);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"server error\"}");
}
缺點:方法必須 void、失去 @ResponseBody 自動序列化、樣板代碼多、易忘編碼設置。
@GetMapping("/user")
public ResponseEntity<Map<String, Object>> getUser(@RequestParam String name) {
Map<String, Object> body = new HashMap<>();
if (StringUtils.isEmpty(name)) {
body.put("error", "name is required");
return ResponseEntity.badRequest().body(body); // 400
}
body.put("name", "zhangsan");
return ResponseEntity.ok(body); // 200
}
// 更多靜態工廠方法
ResponseEntity.created(location).header("X-Custom", "val").body(obj); // 201
ResponseEntity.status(HttpStatus.FORBIDDEN).body(error); // 403
ResponseEntity.noContent().build(); // 204
body + status + headers 完整控制ResponseEntity<T>,配合 @ResponseBody 自動 Jackson 序列化ResponseEntity.ok().header(...).body(...) 鏈式調用restTemplate.getForEntity(uri, String.class) 直接獲取狀態碼與體@RestControllerAdvice
public class GlobalHandler {
@ExceptionHandler(BizException.class)
public ResponseEntity<ErrorResponse> handleBiz(BizException e) {
HttpStatus status = switch (e.getErrorCode()) {
case "AUTH_001" -> HttpStatus.UNAUTHORIZED;
case "PERM_002" -> HttpStatus.FORBIDDEN;
case "RES_003" -> HttpStatus.NOT_FOUND;
default -> HttpStatus.BAD_REQUEST;
};
return ResponseEntity.status(status)
.body(new ErrorResponse(e.getErrorCode(), e.getMessage()));
}
}
| 碼 | 含義 | 典型場景 |
|---|---|---|
| 200 | OK | 成功返回數據 |
| 201 | Created | POST 創建資源,返回 Location 頭 |
| 204 | No Content | DELETE/UPDATE 成功無返回體 |
| 400 | Bad Request | 參數校驗失敗 |
| 401 | Unauthorized | Token 失效/缺失 |
| 403 | Forbidden | 權限不足 |
| 404 | Not Found | 資源不存在 |
| 409 | Conflict | 資源衝突(如唯一鍵重複) |
| 500 | Internal Server Error | 未捕獲異常 |
ResponseEntity<T> 而非直接 T{code, message, timestamp, path}