找回密码
立即注册
搜索
发回帖 发新帖

5368

积分

0

好友

692

主题
发表于 7 小时前 | 查看: 8| 回复: 0

接口改造的时候,最容易遇到一种看起来很奇怪的需求:

“以后所有接口统一改成 POST。”

刚看到这个要求,我第一反应一般不是马上改 Controller。

因为 HTTP 方法不是装饰品,GET、POST、PUT、DELETE 背后都有语义。一个系统突然放弃 REST 风格,所有接口都走 POST,通常不是开发人员偷懒,而是背后有一些现实问题。

我之前也遇到过类似情况。

原来的接口设计挺标准:

GET /user/detail?id=10001

POST /order/create

PUT /user/update

DELETE /user/remove

后来网关层提出要求:

所有业务接口只允许 POST。

刚开始觉得有点反直觉,后来排查下来,原因还真不少。

参数暴露

GET 最大的问题不是不能传复杂参数,而是参数会放在 URL 里面。

比如查询订单:

GET /order/query?userId=10001&status=PAY_SUCCESS&start=2026-01-01

看起来没啥。

但是 URL 会经过很多地方:

  • 浏览器历史记录
  • Nginx access log
  • 网关日志
  • 各种链路追踪系统
  • 甚至一些监控平台都会采集 URL

如果参数里面带用户手机号、业务编号、token,这些信息很容易留下痕迹。

所以有些公司干脆统一 POST,把参数放到 body 里面。

比如:

@PostMapping("/order/query")
public OrderPage query(@RequestBody OrderQueryRequest request) {

    log.info("query order, userId={}", request.getUserId());

    return orderService.query(request);
}

请求:

{
    "userId": 10001,
    "status": "PAY_SUCCESS",
    "startTime": "2026-01-01",
    "endTime": "2026-01-31"
}

至少从接口层面,不会把业务参数直接暴露在 URL。

当然,这不是说 POST 就绝对安全。

HTTPS 才是真正负责传输加密的。POST 只是减少了一些日志污染。

复杂查询

很多项目早期接口设计比较简单:

GET /product/list?page=1&size=20

后来业务越来越复杂。

筛选条件增加:

  • 价格区间
  • 多个分类
  • 标签数组
  • 排序字段
  • 权限条件

最后接口可能变成:

GET /product/list?
category=phone&
tags=a,b,c&
minPrice=1000&
maxPrice=5000&
sort=createTime

URL 越来越长。

有些老系统或者中间代理,对 URL 长度有限制。

比如 Nginx:

large_client_header_buffers 4 8k;

超过限制直接 400。

所以查询类接口很多最后也会改 POST。

Java 里面通常会这么处理:

@PostMapping("/product/search")
public Page<ProductVO> search(@RequestBody ProductSearchDTO dto) {

    if (dto.getPageSize() > 100) {
        throw new IllegalArgumentException("page size too large");
    }

    return productService.search(dto);
}

这种接口本质还是查询,只是 HTTP 方法用了 POST。

这个地方很多新人会纠结:

“POST 不是创建数据的吗?”

理论上是。

但是工程实践里面,为了稳定性,POST 被大量用于复杂查询。

网关治理

微服务环境里面,接口前面一般不是直接挂服务。

链路通常是:

客户端
 |
网关
 |
鉴权服务
 |
业务服务
 |
数据库

网关需要做很多事情:

  • 权限校验
  • 签名验证
  • 流量控制
  • 请求审计
  • 接口灰度

如果 GET、POST、PUT、DELETE 全部存在,网关规则会多很多。

比如:

/user/**
  GET
  POST
  PUT
  DELETE

每种方法都可能有不同策略。

有些公司为了降低治理复杂度,直接规定:

业务接口全部 POST。

网关只需要处理:

POST /*

规则简单很多。

以前排查过一个接口超时问题。

业务日志看不出来。

最后查网关 access log:

2026-03-12 10:21:32
POST /api/order/pay
status=504
cost=30001ms
traceId=8f72xxx

顺着 trace 查下去,发现不是接口慢,而是网关默认只允许 POST body 重放。

某些 GET 请求经过重试组件时,参数丢失了。

统一 POST 后,这类问题少很多。

幂等处理

还有一个容易被忽略的点:POST 更适合统一处理幂等。

很多业务接口其实不是简单 CRUD。

  • 支付
  • 退款
  • 提交任务
  • 批量导入

这些接口即使使用 POST,也必须考虑重复请求。

比如:

用户点击支付按钮。第一次请求成功。网络抖了一下。客户端重新发一次。

如果没有幂等处理,就可能创建两个支付订单。

代码一般会这么做:

@PostMapping("/pay")
public PayResult pay(@RequestBody PayRequest request) {

    String requestNo = request.getRequestNo();

    PayRecord old = payDao.findByRequestNo(requestNo);

    if (old != null) {
        return PayResult.success(old.getPayId());
    }

    PayRecord record = new PayRecord();
    record.setRequestNo(requestNo);
    record.setStatus("PROCESSING");

    payDao.insert(record);

    return paymentService.execute(record);
}

关键不是 POST。

关键是业务唯一号、数据库唯一索引、状态控制。这些才是真正防重复。

不是没有代价

不过,所有接口都 POST 也不是没有问题。

最明显的问题就是语义混乱。

比如:

POST /user/delete

看到这个接口,开发人员不知道它到底是不是幂等。是不是修改数据?是不是需要重试?是不是允许缓存?

另外 GET 天然支持缓存。

浏览器、CDN、代理服务器,都可以根据 GET 做缓存。POST 默认不会缓存。

如果一个接口:

GET /config/version

每天调用几十万次。

改成:

POST /config/version

缓存能力直接没了。

小结

所以实际项目里面,我一般不会简单认为“全部 POST 一定更好”。

要看场景:

  • 内部管理系统
  • 复杂查询系统
  • 强网关治理要求
  • 统一鉴权体系

这些场景全部 POST 很常见。

但是开放 API、公共 REST 接口,还是建议遵守 HTTP 语义。

查询就是 GET,创建就是 POST,修改就是 PUT,删除就是 DELETE。

技术设计很多时候不是追求最优雅,而是在各种限制里面找一个成本最低的方案。

接口规范也是一样。你看到一个系统所有接口都是 POST,不一定是水平低。有可能它经历过代理限制、网关治理、日志安全、跨语言调用之后,最后选择了一个更容易维护的方案。类似的工程取舍思辨,在云栈社区也常有开发者拿出来讨论。




上一篇:DeepSeek Harness dsh-pentest 渗透模式:插件安装、Web 视图与架构详解
下一篇:自由职业一年半:跨境收款到全球复利管道的数字游民实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-22 08:10 , Processed in 0.081388 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表