当后端工程师小张在团队周会上宣布”我们的API已经完全RESTful化”时,他展示的文档里却赫然写着POST /getUserInfo这样的接口。这并非个例——在API设计的世界里,”RESTful”这个词早已被滥用成了”使用JSON的HTTP接口”的代名词。实际上,根据Axway 2024年API行业报告,74%的组织承认其超过20%的API处于未管理状态,而真正达到REST二级成熟度的团队不足10%。
被误读的REST:从RPC沼泽到资源海洋
故事要从某电商平台的订单系统说起。2023年重构前,他们的API文档里充斥着这样的接口定义:
POST /orderService
{
"action": "queryOrder",
"orderId": "12345",
"userId": "789"
}
这就是典型的Level 0(POX沼泽)设计——把HTTP当作传输隧道,所有请求都通过单一端点和POST方法发送,完全无视Web的原生机制。当系统需要新增”撤销订单”功能时,他们只能在请求体里再添加一个”action”: “cancelOrder”的字段。这种RPC风格的设计导致接口文档膨胀到500多页,前端开发者不得不频繁咨询后端”这个接口的参数到底是userId还是user_id”。
Level 1:资源的觉醒
重构第一步是引入资源概念。架构师小李提出将订单、用户、商品等实体抽象为独立资源,每个资源拥有唯一URI:
GET /orders/12345
GET /users/789
POST /orders # 创建新订单
这就是理查德森成熟度模型的Level 1。通过将系统拆解为/orders、/users、/products等资源集合,接口数量从原来的23个爆炸式增长到117个,但每个接口的职责变得单一清晰。最显著的变化是,当新增”订单评价”功能时,团队自不过然地设计出POST /orders/12345/reviews这样的接口,无需再修改原有接口定义。
资源识别小贴士:判断一个API是否达到Level 1,只需看其URI是否都是名词且代表具体实体。避免在URI中出现get、create、update等动词,这是RPC思维的典型残留。
Level 2:HTTP动词的正确打开方式
尽管资源URI解决了接口膨胀问题,但团队很快发现新的混乱——所有接口仍在使用POST方法。前端开发者抱怨:”为什么查询订单和创建订单都是POST?我怎么知道哪个有副作用?”
这时他们才意识到HTTP动词的重大性。根据REST规范,GET用于查询(无副作用)、POST用于创建、PUT用于全量更新、DELETE用于删除。重构后的订单API变成:
GET /orders/12345 # 查询订单
POST /orders # 创建订单
PUT /orders/12345 # 更新订单
DELETE /orders/12345 # 删除订单(逻辑删除)
更关键的是状态码的正确使用。之前所有响应都是200 OK+自定义错误码,目前改为:
- 200 OK:请求成功
- 201 Created:资源创建成功
- 404 Not Found:资源不存在
- 409 Conflict:资源冲突(如重复创建)
这个改变解决了一个长期困扰团队的问题——异步任务处理。当订单支付需要异步处理时,他们设计了:
POST /payments
HTTP/1.1 202 Accepted
Location: /payments/456
前端通过Location头轮询支付结果,而非之前的”轮询同一个接口+业务状态判断”的hack方式。达到Level 2后,系统的缓存命中率提升了40%,由于GET请求可以被CDN有效缓存。
常见误区警示:51CTO的调查显示,73%的团队仍在犯”所有错误都返回200 OK”的低级错误。正确使用状态码不仅能提升性能,更能让客户端自然理解错误类型——4xx错误提示客户端修正请求,5xx错误提示服务端问题。
REST与RPC的楚河汉界
为什么那么多团队止步于Level 1?由于他们构建的实则是”披着HTTP外衣的RPC”。以用户认证为例:
RPC风格:
POST /authService
{
"method": "login",
"params": {"username": "xxx", "password": "yyy"}
}
REST风格:
POST /sessions
{
"username": "xxx",
"password": "yyy"
}
两者的本质区别在于:REST关注资源的状态转移,而RPC关注方法调用。AWS架构师在对比分析中指出,REST的无状态特性使其天然适合分布式系统,而RPC的紧耦合特性在微服务架构中会导致”牵一发而动全身”的问题。

某支付平台的案例很有说服力:他们将服务间通信从RPC迁移到REST后,服务扩容时间从小时级缩短到分钟级,由于每个REST请求都包含了完整上下文,无需依赖服务间的会话状态。
攀登Level 3:HATEOAS的艺术
当团队以为达到Level 2就是REST终点时,新的挑战出现了——移动端需求频繁变化导致接口版本爆炸。iOS端用/v1/orders,Android端用/v2/orders,后端不得不维护多套代码。
这正是HATEOAS要解决的问题。HATEOAS(超媒体作为应用状态引擎)的核心思想是:服务器通过响应中的链接指导客户端下一步操作,而非客户端硬编码URI。
Spring HATEOAS实现的订单API示例:
{
"orderId": "12345",
"status": "paid",
"totalAmount": 99.00,
"_links": {
"self": {"href": "/orders/12345"},
"cancel": {"href": "/orders/12345/cancel", "method": "POST"},
"refund": {"href": "/orders/12345/refund", "method": "POST"},
"track": {"href": "/orders/12345/tracking"}
}
}
当订单状态变为”shipped”时,响应会自动移除”cancel”链接,添加”confirmReceipt”链接。这种动态发现机制让客户端无需感知API版本变化,极大降低了前后端耦合。

GitHub API是HATEOAS的典范。访问https://api.github.com会得到所有可用API的链接,客户端只需记住一个入口点,后续操作全通过链接指引。这种设计使GitHub API从未出现过破坏性更新,尽管其功能已迭代了十余年。
从Level 0到Level 3的进化路径
诊断当前成熟度的三个关键问题
- URI测试:随机挑选3个接口URI,是否都由名词组成?是否包含动词?
- 方法测试:查询操作是否使用GET?创建操作是否使用POST?
- 链接测试:响应中是否包含可操作的资源链接?
如果三个问题的答案都是”否”,那你大致率还停留在Level 0。
渐进式提升策略
Level 0→Level 1(1-2周):
- 梳理系统核心实体,创建资源URI清单
- 将所有RPC接口按资源拆分,如/userService拆分为/users、/profiles等
Level 1→Level 2(2-4周):
- 按CRUD操作映射HTTP方法
- 整理常见业务场景与HTTP状态码对照表
- 添加全局异常处理器,统一状态码返回逻辑
Level 2→Level 3(1-3个月):
- 引入Spring HATEOAS或类似库
- 从核心业务流程开始添加链接关系
- 实现基于链接的API文档自动生成
API成熟度与业务价值的正相关
某电商平台的实践数据显示,API成熟度每提升一个级别:
- 接口文档维护成本降低60%
- 前后端协作效率提升45%
- 系统扩展性提升35%
- 线上接口错误率降低50%
这印证了Roy Fielding在REST论文中强调的观点:架构风格的选择直接影响系统的可扩展性、可见性和可靠性。当你的团队还在为接口版本管理焦头烂额时,那些达到Level 3的系统早已通过HATEOAS实现了无缝进化。

REST不是神器,但值得追求
REST成熟度模型不是教条,而是协助我们构建更好系统的工具。并非所有系统都需要达到Level 3——内部管理系统可能Level 2就足够,而开放平台API则强烈提议实现HATEOAS。
真正的挑战不在于技术实现,而在于思维转变——从”方法调用”到”资源交互”,从”命令式”到”声明式”。当你开始自然地说出”获取订单资源”而非”调用订单接口”时,就说明REST的理念真正融入了你的设计哲学。
正如Martin Fowler所言:”REST的最大价值不在于它的技术细节,而在于它教会我们以Web的方式思考系统设计。”在API驱动开发的时代,提升REST成熟度或许不是最紧急的任务,但绝对是最值得长期投入的架构决策。



我一直认为后端服务端口应该是一个完整独立的业务逻辑。比如删除这种接口怎么可以独立存在?我要新增一个东西然后删除一个,难道调用两次接口?事务怎么保证一致性?
最后都是一个post走天下
只用post json爽歪歪,restful可以滚了
吃过亏的都知道实际项目里只用post和get准没错
业务写多了,就知道这东西也不实用,一个url 4种方式,到后台也得4个接口来接
RPC和rest只是两种接口定义形式。跟是否耦合关系不大。用RPC也能定义松耦合的接口,用rest也能整出耦合得一塌糊涂的系统。
全部post,返回200,错误码code自定义,其他的别纠结了,再晚点老板就要破产了
只用get和post是最好的
没必要强行来,自增烦恼,前端路由按这个风格来还差不多,后端接口还是要从名称上一眼清晰明了
没有哪个接口正好是增高删查这几种,有时候一个查询就有十几种不同的接口,你不在名称上写清楚最后自己也搞不清楚该用哪个接口。。。
restful api简直是网关的噩梦。把id放在path里,一旦需要对公网暴露,网关就需要正则匹配,白白浪费cpu。不但性能差,而且很难防爬虫和bot。忠告:url需要清晰明确的定义,绝对不要把变量放到url里面。restful就是垃圾。
最大的问题还是复杂场景下的查询
RESTful跟安全就是冲突的,越是有规律的系统,越容易被攻克(甚至是自动化的),越是混沌的系统,越难以找到攻克方向,路径和实际作用牛头不对马嘴的接口往往很难被侵入,你以为这是个吹风机,实际上是个刮胡刀
有些查询需求,需要提交很多参数,如果用get的话,处理起来麻烦,而且有可能超出范围。比如房产中介,对于房源的查询,需要很多条件。如果使用post,那就没有问题了。另外,查询不需要使用浏览器的缓存,而get,默认是使用缓存的 ,这个 不麻烦吗?rest适合处理简单的需求。当然,不是说不能处理复杂的,而是说,处理复杂需求,对程序员(设计师)的要求就非常高了。另外,关于状态。我觉得应该明确分为两种:1.业务状态,由业务程序员负责2.通讯状态,由运维负责。通讯状态,当然使用200,404,5xx,这类的了。而业务状态,使用 200 + 内部定义。这样就可以明确区分了。如果是200,还有问题,那么就去找复杂业务的程序员,不用去麻烦运维。而看到非200的,先找运维。理由如下:js代码》浏览器 》》 web服务器 》处理业务需求(业务服务器) 》处理数据需求(数据库)如果通讯出现问题,那么在web服务器就被处理完毕了,不会给业务服务器。如果通讯没有问题,才会交给业务服务器处理。既然这样,业务就不要动通讯状态的代码。
安全扫描怎么要求就得怎么改
REST是一种架构风格,简单讲就是先想清楚你的服务提供哪些“东西”,每个东西都有明确的唯一标志URL,对这些URL提供一套统一的操作动词——因此现代浏览器可以打开全球所有的网站是by design。做个形象类比:游戏手柄几个按钮可以玩转各种游戏也是by design——或者想象一下每个游戏都需要一个按键不同的手柄,或者主机每次升级都要换一个体积更大按键更多的手柄会是什么感觉
这玩意在PPT上写一下就行了,实际开发全走post
我还遇到了这样一个实际情况,IT 安全团队挂截了 DELETE,PUT等方法,只能用 GET和 POST,你还怎么 restful?
有没有可能当大家都用level1的时候说明大家都觉得这样是最方便的况且现在那么多接口维护工具不够用吗大家用的舒服就行别那么死脑筋
restful只适合做个业务超级简单的系统,复杂系统里查询条件url长度都不够咋get