最近在公司碰到一個(gè)挺“突然”的需求,就是領(lǐng)導(dǎo)一句話(huà):以后所有接口都統(tǒng)一用 POST
,不能再用 GET
了。剛聽(tīng)到的時(shí)候大家都一愣,明明 RESTful 不是建議 GET 查數(shù)據(jù)、POST 改數(shù)據(jù)嗎,怎么還要“一刀切”?但深入聊完之后,發(fā)現(xiàn)其實(shí)背后有不少坑。
GET 和 POST 的區(qū)別到底在哪
從協(xié)議層面說(shuō),GET
參數(shù)是跟在 URL 上的 query string,比如 /search?keyword=Java
,而 POST
的參數(shù)放在請(qǐng)求體里。兩者雖然都能傳參,但差別挺大:
- GET 的參數(shù)很容易被日志打出來(lái),尤其是在 Nginx、網(wǎng)關(guān)、監(jiān)控鏈路里,敏感數(shù)據(jù)直接裸奔;
- GET URL 有長(zhǎng)度限制,不同的瀏覽器、代理、甚至 Tomcat 都會(huì)卡上限,超過(guò)就直接截?cái)啵?/span>
- GET 請(qǐng)求可能被瀏覽器、CDN 緩存,結(jié)果就是用戶(hù)明明操作了新數(shù)據(jù),接口卻還返回老結(jié)果。
這些風(fēng)險(xiǎn)在小項(xiàng)目里可能無(wú)所謂,但一旦上了生產(chǎn)環(huán)境,出事故的幾率比你想象中大。
Java 里實(shí)際寫(xiě)法對(duì)比
比如之前我們寫(xiě)一個(gè)搜索接口,最常見(jiàn)就是 GET:
@GetMapping("/search")
public List<String> search(@RequestParam String keyword) {
return searchService.find(keyword);
}
這樣寫(xiě)沒(méi)啥問(wèn)題,但如果 keyword 太長(zhǎng),或者用戶(hù)輸入里有奇怪的字符,就容易觸發(fā) URL 截?cái)?,或者被日志全量打印?/span>
改成 POST 的話(huà),參數(shù)就放 body 里了:
@PostMapping("/search")
public List<String> search(@RequestBody SearchRequest request) {
return searchService.find(request.getKeyword());
}
public class SearchRequest {
private String keyword;
// getter setter
}
好處是:參數(shù)再多再長(zhǎng)都不怕,body 天然支持復(fù)雜結(jié)構(gòu),后續(xù)擴(kuò)展也方便。
來(lái)個(gè)日志對(duì)比的小 demo
為了讓大家直觀(guān)感受下區(qū)別,我在 Spring Boot 項(xiàng)目里加了一個(gè)簡(jiǎn)單的日志攔截器,把請(qǐng)求信息打出來(lái)。
攔截器代碼:
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("請(qǐng)求方法: " + request.getMethod());
System.out.println("請(qǐng)求URL: " + request.getRequestURL());
System.out.println("請(qǐng)求參數(shù): " + request.getQueryString());
return true;
}
}
配置一下就能生效,然后試試:
GET 請(qǐng)求:http://localhost:8080/search?keyword=Java&token=abc123
日志里會(huì)直接打?。?/span>
請(qǐng)求方法: GET
請(qǐng)求URL: http://localhost:8080/search
請(qǐng)求參數(shù): keyword=Java&token=abc123
你看,token 直接暴露出來(lái)了。
POST 請(qǐng)求: 請(qǐng)求體:
{
"keyword": "Java",
"token": "abc123"
}
日志打?。?/span>
請(qǐng)求方法: POST
請(qǐng)求URL: http://localhost:8080/search
請(qǐng)求參數(shù): null
參數(shù)在 body 里,不會(huì)被 query string 打出來(lái),至少不會(huì)在常規(guī)日志里裸奔。
為什么要突然“一刀切”
安全部門(mén)其實(shí)考慮的就是這幾點(diǎn):
- 避免敏感信息被 URL 記錄在各類(lèi)日志里。
- 規(guī)避 URL 長(zhǎng)度上限問(wèn)題,尤其在復(fù)雜業(yè)務(wù)場(chǎng)景。
- 統(tǒng)一規(guī)范,后續(xù)接網(wǎng)關(guān)、審計(jì)、監(jiān)控都更容易。
我自己還遇到過(guò)一個(gè)血的教訓(xùn):因?yàn)?GET 參數(shù)太長(zhǎng),被網(wǎng)關(guān)直接截?cái)啵瑢?dǎo)致用戶(hù)下單失敗,查了半天才發(fā)現(xiàn)是 URL 超長(zhǎng)的問(wèn)題。如果當(dāng)時(shí)用 POST,這事兒根本不會(huì)發(fā)生。
所以說(shuō),這波統(tǒng)一雖然一開(kāi)始看著麻煩,但長(zhǎng)期來(lái)看能省掉不少坑。GET 不是不能用,以后可能就只留給靜態(tài)資源、健康檢查這種輕量場(chǎng)景,業(yè)務(wù)接口還是老老實(shí)實(shí) POST 穩(wěn)妥。
閱讀原文:原文鏈接
該文章在 2025/10/17 17:37:14 編輯過(guò)