写API这事儿,我见过太多「技术债」现场了

2026-06-26 12 0

写API这事儿,我见过太多「技术债」现场了

作为一个写过无数接口的老油条,今天必须来聊聊API设计里那些让人头秃的烂设计。不是为了喷而喷,是真的见过太多项目被糟糕的API设计拖垮到重构的。看完这篇,希望你的下一个接口不要成为别人的噩梦。

一、RESTful?不是你想怎么用就怎么用的

现在出去面试,开口就是「我们的API是RESTful的」。好,RESTful很好,但不是你说RESTful就RESTful的。很多人对RESTful的理解就是:URL里放名词,HTTP方法用GET/POST/PUT/DELETE,然后自称精通RESTful了。

大哥,你连HATEOAS都没听说过,Hypermedia都不支持,算什么RESTful?

最常见的问题是什么?用一个GET方法干所有事情。查列表用GET,查详情用GET,删数据用GET(传个delete参数),甚至改数据也用GET。你问为什么?他说「GET更安全,浏览器直接能打开」。每次听到这种回答我都想原地升天。

真实案例:某项目查用户详情是 GET /api/getUser?id=123,问他为什么不用 GET /api/users/123,他说「怕用户记不住」。兄弟,你是怕你自己记不住RESTful怎么写吧?

HTTP语义不是摆设。GET就是幂等的、只读的;POST是创建资源的;PUT是更新完整资源的;PATCH是部分更新的。把这些用对了,至少你的API不会让人看了一脸问号。

二、命名:说好的人能看懂呢?

API命名这事儿吧,说难听点,有些接口命名纯属程序员自嗨。团队内部可能大家都知道啥意思,但凡有个新人进来,或者对接别的团队,那个命名就是灾难。

举几个我见过的奇葩命名:

  • 拼音+英文混搭型:/api/getUserList、/api/getUserInfo、/api/getUserDetail — info和detail有什么区别?list和detail又有什么区别?
  • 缩写狂魔型:/api/qryUsr、/api/updUsrInfo、/api/delUsr — 你是怕别人看懂你在干什么吗?
  • 动词堆积型:/api/getUserDataById、/api/getUserDataByName、/api/getUserDataByPhone — 能不能统一一下?

好的命名应该是什么样的?

  • 名词复数形式:/users、/orders、/products
  • 层级结构清晰:/users/{userId}/orders(用户的所有订单)
  • 不用拼音,用英文单词
✅ 正确示范:GET /users/123/orders — 获取ID为123的用户的所有订单❌ 错误示范:GET /api/getUserOrderList?userId=123

三、HTTP状态码:200真的不是万能的

这个问题我见过无数次了:接口报错了,返回200,业务状态码写个-1或者「error」。拜托,HTTP状态码就是用来处理异常情况的,你非要用200包着错误信息返回,让客户端判断到底是成功还是失败,这不是脱了裤子放屁吗?

常见的状态码混乱:

  • 资源不存在:返回200 + {code: 404, message: "not found"} — 你是在玩大家来找茬吗?
  • 参数校验失败:返回200 + {code: 400, message: "参数错误"} — 前端看到这个200还以为成功了
  • 服务器崩了:返回500 + 空响应体 — 客户端解析JSON直接报错

正确的做法是什么?

✅ 成功GET /users/123200 OK{ "id": 123, "name": "张三", "email": "zhangsan@example.com" }✅ 资源不存在GET /users/999404 Not Found{ "error": "用户不存在", "code": "USER_NOT_FOUND" }✅ 参数校验失败POST /users400 Bad Request{ "error": "邮箱格式不正确", "code": "INVALID_EMAIL" }✅ 服务器错误GET /users500 Internal Server Error{ "error": "服务暂不可用", "code": "SERVICE_UNAVAILABLE" }

四、版本管理:没版本号的API都是在耍流氓

很多人觉得「我的API就这么一套,不用版本管理,多干净」。好,你想得美。等你哪天要加字段、改逻辑、删参数的时候,你就知道疼了。老客户端不兼容,新客户端用不了,线上事故就来了。

版本号放哪儿?常见的有三种:

  1. URL路径:/api/v1/users — 最直观,最常见
  2. Query参数:/api/users?version=1 — 不推荐,容易被忽略
  3. Header:Accept: application/vnd.api+json;version=1 — 规范但不够直观

我个人推荐URL路径的方式,简单粗暴,一目了然。访问/v1/users就知道是老版本,/v2/users就是新版本。

冷知识:GitHub的API就是URL路径版本管理。访问 api.github.com/v3/users 是老版本,api.github.com/users 是新版本(其实v3存在了很多年)。这才是正经大厂的做法。

五、返回结构:标准化是基本礼仪

很多项目的接口返回结构是这样的:

// 接口A{ "code": 0, "msg": "成功", "data": { ... } }// 接口B{ "status": "ok", "result": { ... } }// 接口C{ "success": true, "info": { ... } }// 接口D{ ... } // 直接返回数据,没任何包裹

五个接口五种返回格式,前端每次对接新接口都要写一堆特殊处理代码。这就是没有统一响应结构的后果。

强烈建议所有接口统一响应结构:

{ "code": 0,           // 业务状态码,0表示成功 "message": "success", // 描述信息 "data": { ... }       // 业务数据}

分页列表也要统一:

{ "code": 0, "message": "success", "data": { "list": [ ... ], "pagination": { "page": 1, "pageSize": 20, "total": 100, "totalPages": 5 } }}

统一了格式,前端封装一个axios拦截器,所有的错误处理、loading状态、异常提示都可以统一处理。它不香吗?

六、安全:你的API被陌生人访问过吗?

这个话题很多人觉得自己做得很好,其实漏洞一堆。我来说几个常见的:

1. 没有参数校验

前端说「我做了校验」,然后后端直接存进数据库。结果SQL注入、XSS攻击了解一下?前后端校验都要做,后端不能信任任何前端传来的数据,这是基本常识。

2. 越权访问

// 危险示例GET /api/orders/456// 返回了这个订单的完整信息,包括其他用户的订单// 正确做法:后端要校验当前登录用户是否有权限访问这个订单if (order.userId !== currentUser.id) { return 403 Forbidden; }

3. 敏感信息明文传输或明文存储

密码加密了吗?身份证号加密了吗?手机号加密了吗?日志里打印了完整token了吗?这些细节不注意,出了事就不是技术问题了,是法律问题。

七、写到最后

API设计这事儿,说难听点就是「前人挖坑,后人填坑」。你在设计的时候多花10分钟,后人可能就少掉1小时头发。

几个核心原则记住:

  • 语义清晰:HTTP方法用对,状态码用对
  • 命名规范:统一、可读、不歧义
  • 结构统一:响应格式标准化
  • 版本意识:预留扩展能力
  • 安全第一:校验、鉴权、加密一个都不能少

好的API是沉默的——调用者不需要看文档就能猜到怎么用,错误信息清晰到能直接定位问题,返回格式统一到可以一键封装。这才是后端该追求的境界。

少写点「能用就行」的代码,多想想未来维护你代码的人会不会半夜爬起来骂你。代码千万行,API第一关。祝大家的接口都能平平安安上线,稳稳当当运行。

相关文章

AI浪潮里捞点有意思的:OpenClaw与奇奇怪怪的AI玩法
EXPLAIN 告诉你的全是屁话——除了这一行
服务又双叒叕慢了?我用这四招把响应时间从20秒打到了200毫秒
写了三年API,我把这些坑都踩了一遍
为什么 SQL 写得好的人,数据库依然慢给你看
还在为部署AI工具头秃?我来帮你搞定一切

发布评论