为什么所有接口都用POST?

RESTful API的局限

RESTful当初的设计目标是解决互联网级别的信息共享和互操作问题。而我们的大量开发者工作的主要目标是“为业务系统实现一个满足功能(比如登录,交易……)/非功能需求(比如认证,性能,可扩展性……)的接口“。

  • REST只提供了增删改查的基本语义,其他的语义基本上不管。比如批量添加,批量删除,修改一个资源的一部分字段。区分“物理删除”和“标记删除”等等。复杂的查询更加不显示,对于像筛选这类的场景,REST明显就是个渣。这里要表扬一下GraphQL(但GraphQL有其他的问题,在此不展开)。“标记删除”应该用PUT还是DELETE?
  • REST建议用HTTP的status code做错误码,以便于“统一”,实际上这非常难统一。各种业务的含义五花八门,抽象层次高低不齐,根本就无法满足需要。比如一个404到底是代表这个接口找不到,还是代表一个资源找不到。400表达请求有问题,但是我想提示用户“你登录手机号输入的格式不对“,还是“你登录手机号已经被占用了“。既然201表示“created”,为啥deleted和updated没有对应的status code,只能用200或者204(no content)?错误处理是web系统里最麻烦的,最需要细心细致的地方。REST风格在这里只能添乱。
  • web请求参数可能散布在url path、querystring、body、header。服务器端处理对此完全没有什么章法。客户端和服务器端的研发之间还是要做约定。
  • 在url path上的变量会对很多其他的工作带来不良影响。比如监控,本来url可以作为一个接口的key统计次数/延迟,结果url里出了个变量,所以自动收集nginx的access log,自动做监控项目增加就没法弄了。再比如,想对接口做流量控制的计数,本来url可以做key,因为有变量,就得多费点事才行。
  • 现实中接口要处理的真正的问题,REST基本上也没怎么管。比如认证、授权、流控、数据缓存(http的etag还起了点作用)、超时控制、数据压缩……。
  • REST有很多好的工具可以便利的生成对应的代码和文档,也容易形成规范。但问题是REST在实际的项目中并没有解决很多问题,也在很多时候不合用,因此产生的代码和文档也就没什么用,必须经过二次加工才能真的用起来。因此可以基于REST+你的业务场景定义一个你自己的规范。

将业务过程转成资源状态变化本身就比较烧脑,而且存在无法转化的场景。总结下来就是:世界很复杂,REST太简单。如果上 REST,最终会演变成一个不伦不类的系统。

如何选择及接口方案?

作为技术负责人,如果他搞出了一套接口方案(也许其中一条就是所有http接口都用post),提高了开发效率,降低了沟通成本,降低了运维和错误定位成本,为企业真正做到了降本增效。把瞎折腾的成本,投入到了其他比如业务架构设计,测试体系,线上监控,容灾降级等领域上。最终让企业(用户需求得到满足,收入增加)和员工得到了收益(因为公司收入增加而涨薪)。我会评价这样的人为“真正懂架构,懂技术,善于用技术解决实际问题。水平不知道高到哪里去了“。

如果一个技术负责人只知道遵守一个书上写的,但从没验证过在自己的环境有效的方案,以至于让企业的核心目标无法达成。他就是赵括,该马上卷铺盖卷走人。至于我司,使用的规范是。

对于动态业务接口,只有一个接口 POST /action,在Header里给X-Action给出具体的接口名称交给网关路由,session表示用户登录身份,以及用于推荐、防重、染色、安全用到的各种token/签名。所有的业务请求参数都以PB编码后放在请求体里,并和后端的gRPC体系衔接。接口除了防重试之外,不提供常规意义上的Cache。而对于静态接口,走CDN,做多级Cache。该用Get用Get。如果一个动态接口也想利用http层Cache,可以向网关申请和配置。有没有Cache,cache多久是网关和端上自己实施的,完全自己管控。

GET 与 POST的区别

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST么有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。

如上所说,GET 可能存在一些问题,所以不如 POST。现在比较流行的 grpc 本质上也是 http post 请求。

引用

从业早期都是遵守restful规范的,后来觉得实在是脱了裤子放屁多此一举。现在希望所有项目都走纯post json rpc。
有答主说,rest和json rpc只是接口风格不同。其实不是这样的,两者有实质不同,rpc是普适的,rest能覆盖的范围则小得多。
rest全名就强调了“资源”的状态转移,它是默认服务于对“资源”的crud操作的。玩rest的人特别擅长通过各种神奇的脑洞,把一切操作都转着弯儿解释为资源的crud,以适应rest这一先天限制。换个人就换种不同的解释,结果就是每个人的rest定义都不一样,头疼。。。
本质上讲,rest提出的时候,甚至互联网刚刚出现的时候,人们都是把网页后台的服务仅仅当做一个资源读写的服务器的,基本上近似于把后台逻辑理解为直接处理一张张数据库的table。不仅仅是rest,我们现在再看uri或url这些概念的设计初衷,也是一股机械的静态资源味儿。可是现在时代早就不同了。从前网页上只是看看图文填个表单而已,现在你访问一个url说不定就能发射核弹呢。。。
还有答主纠结幂等的操作要用get和put。。拜托,这是rest的规定,不是http的规定。只要敢于抛弃rest这一桎梏,幂等不幂等用啥method还不都是你说了算的?
最后,对于复杂的多种资源联动的crud,对于那种一个请求就导致后台读一堆资源写另一堆资源的情况,rest也没法表达,所以facebook改玩graphql了,背后就是一个post打天下
有人问,那get缓存怎么办?缓存这种东西还是不要交给浏览器和http协议的好吧,太不好控制了。真正需要缓存的时候,我会在前端里搞类似apollo client或react query那样的缓存,或者在后端应用层或redis层搞,可以精确地控制何时把哪些过期的缓存干掉。人生苦短,单单为了一个http协议就维护一套管理query string和cache header的转换层,感觉不值得。都搞成跨协议通用的缓存管理代码,挺好。