踩坑合集!2025 年常見的 16 個(gè) REST 狀態(tài)碼錯(cuò)誤,你中了幾個(gè)?
狀態(tài)碼不是“隨便寫個(gè) 200 就完事”的擺設(shè)
構(gòu)建一個(gè)高可用、高可維護(hù)的 REST API,從來不只是把功能“跑通”那么簡(jiǎn)單。對(duì)于返回給客戶端的 HTTP 狀態(tài)碼,很多開發(fā)者(包括我自己)在初期都掉進(jìn)了“200 一把梭”的誤區(qū)。一開始我也這么做:用戶點(diǎn)擊“生成報(bào)告”,這個(gè)操作比較耗時(shí),我直接返回一個(gè) 200 OK + “稍等,馬上好”作為反饋,自以為穩(wěn)了,結(jié)果被新入職的小伙伴一句“你這不是應(yīng)該用 202 Accepted 嗎?”當(dāng)場(chǎng)點(diǎn)醒。
為了搞清楚到底有哪些狀態(tài)碼使用誤區(qū),我翻了 RFC 7231、研究了一些最佳實(shí)踐、審視了項(xiàng)目代碼,也總結(jié)出了一份“踩坑黑榜”——REST 接口中最容易犯錯(cuò)的 16 個(gè) HTTP 狀態(tài)碼使用場(chǎng)景。不僅如此,我還基于 Spring Boot 3.4 的架構(gòu)給出優(yōu)化實(shí)踐方案,讓我們少走彎路。
無論你是后端開發(fā)、架構(gòu)師還是 API 網(wǎng)關(guān)工程師,這篇文章都能幫你全面排查狀態(tài)碼使用是否規(guī)范。
以下為本次匯總的 16 個(gè)最容易犯錯(cuò)的狀態(tài)碼場(chǎng)景,每個(gè)錯(cuò)誤都附帶優(yōu)化實(shí)踐和建議:
1?? 異步任務(wù)卻返回了 200 OK?
? 錯(cuò)誤示范:
POST /generate-report
HTTP/1.1 200 OK
{"message": "報(bào)告正在生成中"}
? 正確做法:使用 202 Accepted 說明任務(wù)已接收但尚未完成,并返回任務(wù)狀態(tài)查詢鏈接:
POST /reports
HTTP/1.1 202 Accepted
Location: /reports/12345
Content-Type: application/json
{"status": "Processing", "estimated_completion": "30 seconds"}
查詢狀態(tài)時(shí):
GET /reports/12345
HTTP/1.1 202 Accepted
{"status": "Processing", "progress": "70%"}
2?? 請(qǐng)求失敗卻返回了 200?
? 錯(cuò)誤示范:
HTTP/1.1 200 OK
{"status": "error", "message": "找不到用戶"}
? 正確做法:使用具體錯(cuò)誤碼,如:
- 400 Bad Request:輸入?yún)?shù)有誤
- 401 Unauthorized:未認(rèn)證
- 404 Not Found:資源不存在
3?? 使用 302 Found 重定向 POST?
? 錯(cuò)誤示范:POST 提交后返回 302,可能導(dǎo)致表單重復(fù)提交。
? 正確做法:使用 303 See Other 告知客戶端重定向到 GET 頁(yè)面。
4?? 使用 404 來掩蓋方法不支持?
? 錯(cuò)誤示范:
DELETE /users/123
HTTP/1.1 404 Not Found
? 正確做法:使用 405 Method Not Allowed,并提供 Allow 頭:
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST
5?? 所有錯(cuò)誤一律 500?
? 錯(cuò)誤示范:
GET /search?query=
HTTP/1.1 500 Internal Server Error
? 正確做法:針對(duì)客戶端錯(cuò)誤,使用 400 Bad Request 更明確。
6?? 不限流也不返回 429?
? 正確做法:對(duì)接口做限流,達(dá)到閾值返回 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
7?? 數(shù)據(jù)校驗(yàn)錯(cuò)誤卻只返回 400?
? 錯(cuò)誤示范:郵箱格式錯(cuò)誤返回 400。
? 正確做法:使用 422 Unprocessable Entity 表示參數(shù)格式合法但值無效。
8?? 忽略緩存頭?
? 正確做法:結(jié)合 ETag、If-Modified-Since 使用 304 Not Modified 節(jié)省帶寬。
9?? 刪除失敗還說成功?
? 錯(cuò)誤示范:刪除不存在用戶返回 200。
? 正確做法:
- 成功刪除返回 204 No Content
- 對(duì)象不存在返回 404 Not Found
?? 數(shù)據(jù)庫(kù)連接失敗也用 500?
? 正確做法:數(shù)據(jù)庫(kù)不可用返回 503 Service Unavailable,并設(shè)置 Retry-After 頭。
1??1?? 創(chuàng)建成功卻不告訴位置?
? 正確做法:使用 201 Created 同時(shí)提供 Location:
HTTP/1.1 201 Created
Location: /users/123
1??2?? API 被廢棄卻返回 500?
? 正確做法:使用 410 Gone 明確提示接口已廢棄。
1??3?? 未登錄卻說禁止訪問?
? 錯(cuò)誤示范:
HTTP/1.1 403 Forbidden
? 正確做法:使用 401 Unauthorized,提示需要登錄認(rèn)證。
1??4?? 客戶端上傳的格式不對(duì)卻沒提示?
? 正確做法:返回 415 Unsupported Media Type,并告知支持的格式類型。
1??5?? CORS 錯(cuò)誤混淆狀態(tài)碼?
? 正確做法:確保返回正確的跨域頭部,并返回具體錯(cuò)誤而非模糊的 500。
1??6?? 資源沖突也返回成功?
? 正確做法:重復(fù)創(chuàng)建資源時(shí)使用 409 Conflict 提示沖突。
實(shí)戰(zhàn)優(yōu)化建議(Spring Boot 3.4 示例)
控制器異常處理建議:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ApiError("資源不存在", 404));
}
@ExceptionHandler(InvalidInputException.class)
public ResponseEntity<ApiError> handleInvalidInput(InvalidInputException ex) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY)
.body(new ApiError("參數(shù)校驗(yàn)失敗", 422));
}
@ExceptionHandler(RateLimitExceededException.class)
public ResponseEntity<ApiError> handleRateLimit() {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.RETRY_AFTER, "60");
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS)
.headers(headers)
.body(new ApiError("請(qǐng)求過多,請(qǐng)稍后重試", 429));
}
}
返回體結(jié)構(gòu)建議:
public class ApiError {
private String message;
private int code;
public ApiError(String message, int code) {
this.message = message;
this.code = code;
}
// Getter / Setter 省略
}
總結(jié)
一個(gè)優(yōu)秀的 RESTful API,不僅要返回正確的業(yè)務(wù)數(shù)據(jù),還要講究語(yǔ)義清晰、語(yǔ)義準(zhǔn)確。狀態(tài)碼,是 API 與客戶端交流的第一層語(yǔ)言。
使用錯(cuò)誤的狀態(tài)碼,輕則讓前端工程師一臉懵逼,重則引發(fā)安全隱患、重試失敗、用戶體驗(yàn)差……它既是技術(shù)細(xì)節(jié),也代表團(tuán)隊(duì)的工程素養(yǎng)。
如果你在維護(hù)系統(tǒng) API,不妨對(duì)照這 16 個(gè)坑,來一次自查:
- 我們是不是總是用 200 ?
- 遇到校驗(yàn)失敗是不是忘了用 422?
- 緩存返回是不是該用 304?
- 報(bào)錯(cuò)是不是一律甩個(gè) 500?