突然要求所有接口都用 post 请求,为什么?
|
admin
2025年10月15日 23:55
本文热度 123
|
最近在公司碰到一个挺“突然”的需求,就是领导一句话:以后所有接口都统一用 POST
,不能再用 GET
了。刚听到的时候大家都一愣,明明 RESTful 不是建议 GET 查数据、POST 改数据吗,怎么还要“一刀切”?但深入聊完之后,发现其实背后有不少坑。
GET 和 POST 的区别到底在哪
从协议层面说,GET
参数是跟在 URL 上的 query string,比如 /search?keyword=Java
,而 POST
的参数放在请求体里。两者虽然都能传参,但差别挺大:
- GET 的参数很容易被日志打出来,尤其是在 Nginx、网关、监控链路里,敏感数据直接裸奔;
- GET URL 有长度限制,不同的浏览器、代理、甚至 Tomcat 都会卡上限,超过就直接截断;
- GET 请求可能被浏览器、CDN 缓存,结果就是用户明明操作了新数据,接口却还返回老结果。
这些风险在小项目里可能无所谓,但一旦上了生产环境,出事故的几率比你想象中大。
Java 里实际写法对比
比如之前我们写一个搜索接口,最常见就是 GET:
@GetMapping("/search")
public List<String> search(@RequestParam String keyword) {
return searchService.find(keyword);
}
这样写没啥问题,但如果 keyword 太长,或者用户输入里有奇怪的字符,就容易触发 URL 截断,或者被日志全量打印。
改成 POST 的话,参数就放 body 里了:
@PostMapping("/search")
public List<String> search(@RequestBody SearchRequest request) {
return searchService.find(request.getKeyword());
}
public class SearchRequest {
private String keyword;
// getter setter
}
好处是:参数再多再长都不怕,body 天然支持复杂结构,后续扩展也方便。
来个日志对比的小 demo
为了让大家直观感受下区别,我在 Spring Boot 项目里加了一个简单的日志拦截器,把请求信息打出来。
拦截器代码:
@Component
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("请求方法: " + request.getMethod());
System.out.println("请求URL: " + request.getRequestURL());
System.out.println("请求参数: " + request.getQueryString());
return true;
}
}
配置一下就能生效,然后试试:
GET 请求:http://localhost:8080/search?keyword=Java&token=abc123
日志里会直接打印:
请求方法: GET
请求URL: http://localhost:8080/search
请求参数: keyword=Java&token=abc123
你看,token 直接暴露出来了。
POST 请求: 请求体:
{
"keyword": "Java",
"token": "abc123"
}
日志打印:
请求方法: POST
请求URL: http://localhost:8080/search
请求参数: null
参数在 body 里,不会被 query string 打出来,至少不会在常规日志里裸奔。
为什么要突然“一刀切”
安全部门其实考虑的就是这几点:
我自己还遇到过一个血的教训:因为 GET 参数太长,被网关直接截断,导致用户下单失败,查了半天才发现是 URL 超长的问题。如果当时用 POST,这事儿根本不会发生。
所以说,这波统一虽然一开始看着麻烦,但长期来看能省掉不少坑。GET 不是不能用,以后可能就只留给静态资源、健康检查这种轻量场景,业务接口还是老老实实 POST 稳妥。
阅读原文:原文链接
该文章在 2025/10/17 17:37:14 编辑过