Skip to content
On this page

API URI 规范

不要用 RESTful API

RESTful API 只适用于资源型网站,比如 GitHub.com,世上 90% 的网站都不是资源型网站。RESTful API 规范非常理想化,不普适,更不适合中国开发者的快速开发需求,下文有详细解释。

本文讲一个更适合中国国情的、适合快速开发的 API 规范。

Method

4 种 Method

模仿 RESTFul API 规范,严格使用 4 种 Method:

  • 获取:GET

  • 新增:POST

  • 修改:PUT

  • 删除:DELETE

为何使用 4 种而不是简化为 GET 和 POST

使用 4 种 Method 并不是心智负担,确实有区分的必要,因为:

  1. PUTDELETE要追求幂等性,POST不追求。这对后端程序员是一个提醒,开发维护时一目了然。

  2. 新增和修改资源需要传递的内容是不一样的,区分POSTPUT对后端程序员是一个提醒,开发维护时一目了然。

  3. DELETE传参应使用 URL 查询,POST不是,即使都用POST,开发的时候照样要区分传参方式,所以干脆区分使用POSTDELETE,开发维护时更一目了然。

  4. 从浏览器Network可以直接看到Method(没有的话需要右击开启),当请求很多时,请求列表会很乱,此时PUTDELETE会被视线第一时间扫到,可以减少心智负担。

复杂业务 API 如何确定使用哪个 Method

有时候查询、新增、修改在一个接口中同时发生,则根据业务性质和幂等性确定使用哪个 Method。

比如 Login 接口会返回 token,虽然它有返回数据,但是因为这个接口主作用是新增登记,所以应使用POST

同理,新增一条记录显然使用POST,然后接口返回新增的记录的id,你不能说因为它返回了有意义的数据,就说它是GET,况且,从幂等性来说,一次和多次调用接口的结果是不一样的。

URL

Chrome 的“Network”应显示“Name”、“Path”还是“URL”?

Chrome 浏览器的Network可以显示NamePathURL中的一个或多个,而且,当点击一个请求查看详情时,只会显示其中的一个,所以现在我们需要抉择显示哪一个:

  • URL的缺陷在于它太长了,信息冗余,增加心智负担。

  • Path虽然不长,长度挺恰当,但是缺陷是不带 URL 参数。

  • Name没有以上问题,它长度恰当,也带 URL 参数,所以应只显示Name

接下来的问题就是:如何规范接口 URL,让Name最清晰、一目了然、减少心智负担。

RESTful API 规范的缺陷

RESTful 规范在NetworkName的表现如下,你可以看到 2 个/123,2 个/user

Method路径的 RESTful 写法举例Name
GET/manage/system/user/123?.../123?...
POST/manage/system/user/user
PUT/manage/system/user/user
DELETE/manage/system/user/123/123

只显示Name的话,你会发现一些心智负担:

  1. 看不出123是什么资源的123

  2. 看不出/user是什么操作,只能结合 Method 才能发现是POST还是PUT操作。

  3. PUT /user可能代表多种操作,比如修改基本信息、用户禁言,如果前者只修改一个数据表,后者修改多个数据表,按照中国开发者的习惯,应分成 2 个接口,这时候只用PUT /user无法明确表达,需要再结合请求体综合判断。

其他某些劣质规范的缺陷

一些程序员习惯使用GET /user/list来获取资源列表,这样的话Name显示为/list,因为网站打开时会加载多个list资源,导致Name列出现多个/list,更看不出是什么资源,增加心智负担。

本文规范详情

  1. 关于接口的路径

👎 REST:路径一律是/api/manage/system/user,禁止使用动词。

👍 本文:应使用动词名词修饰词写法,比如:

  • 获取用户使用GET /api/manage/system/user/getUserList

  • 新增用户使用POST /api/manage/system/user/addUser

  • 修改用户使用PUT /api/manage/system/user/editUser

  • 删除用户使用DELETE /api/manage/system/user/delUser?id=123

  • 如果有多种PUT操作,可以使用更加明确的动词单词,比如禁言叫/api/manage/system/user/banUser

  • 修饰词举例:获取被封禁的用户使用GET /api/manage/system/user/getUserBanned

  1. 关于接口的参数

👎 REST:参数使用/:id结构,比如:/api/manage/system/user/123

👍 本文:参数应使用 URL 查询的写法:/api/manage/system/user?id=123

本文规范优势

现在我们再来对比一下,看看 RESTful 规范和本文规范在浏览器Network呈现的Name的区别:

MethodRESTful 写法本文规范写法
GET 查列表/system/user/orgId/123/system/user/getUserList?orgId=123
Name👎/123👍/getUserList?orgId=123
GET 查 Tree/system/user/orgId/123/system/user/getUserTree?orgId=123
Name👎/123👍/getUserTree?orgId=123
GET 带修饰词/system/user/banned/system/user/getUserBanned
Name👎/banned👍/getUserBanned
GET 查单条/system/user/123/system/user/getUser?id=123
Name👎/123👍/getUser?id=123
POST/system/user/system/user/addUser
Name👎/user👍/addUser
PUT/system/user/system/user/editUser
Name👎/user👍/editUser
DELETE/system/user/123/system/user/delUser?id=123
Name👎/123👍/delUser?id=123

接口尽量避免跨域

以当前 API 请求的行业通用惯例来说,一旦跨域,一定是非简单请求,因为简单请求必须符合以下特征:

  1. 请求方式只能是:GETPOSTHEAD(如果打算迁就此特征,可以将PUTDELETE改为POST

  2. HTTP 请求头限制这几种字段:AcceptAccept-LanguageContent-LanguageContent-TypeLast-Event-ID(无法迁就,因为一定要有一个其他字段比如Authorization用于传递 Token)

  3. Content-type只能取:application/x-www-form-urlencodedmultipart/form-datatext/plain(如果打算迁就此特征,行业惯例是使用Content-Type: application/json;charset=UTF-8,虽然可以改为application/x-www-form-urlencodedmultipart/form-data,但更麻烦)

总之,受制于第 2 条,注定无法使用简单请求,而非简单请求会发送预请求,很山寨的感觉。

所以,要么接口尽量避免跨域,要么忍受浏览器发送OPTIONS请求。

杨亮的前端解决方案