RESTful API 中的 Status code 是否要遵守规范

2019-02-22 09:58:06 +08:00
 Muninn

缘起

事情是这样的,我在知乎受到邀请回答一个问题,主要是问 ID 找不到到底要不要用 Status 404。我回答的还是比较早的,那时候只有一两个回答。我本来以为这是没啥争议的,在一个学术的地方讨论学术问题,当然是要遵守规范了,结果过了几个小时大跌眼镜。自造 code 党竟然支持率第一,还好平时见的也很多的全 200 党没有受到支持,不然真的吐血了。

为什么要遵守规范

一般那种说特殊情况特殊处理,不要拘泥于规范的人,大多都是自己没搞清楚某些知识,拿这句话当作偷懒的借口。其实一般做项目没那么多特殊情况。

为了更好的适应各种库

大部分完善的 HTTP 请求库,都会依照 RFC 的规范去设计错误处理的流程,虽然处理方式各有不同,但一定会在文档说明错误处理的部分的。使用 RFC 标准能最大限度的兼容各种 HTTP 客户端。你说现在你用的 HTTP 客户端不处理 Status Code,但是你没法保证将来不重构,重构的时候还是不处理。

一般调用 api 使用 js 或者 python 的概率比较大,我们看看知名的库。在 js 里,最近比较流行的 axios 默认会把 200 系列外的 code 归到异常里。在 python 里,最流行的 http client 是 requests,它更为详尽的预处理了 status code。

为了开发者更好上手

另外在管理团队的方面,我们的原则是尽量的减少一个项目的“规范”,这样才能更容易去遵守。能用标准的地方,一定不要自己定一个更复杂的规则。无论是服务端的维护者还是 API 的消费者是会换人流动的,每个进入项目的人熟悉一大堆无谓的自定义项目规范都要成本。

更简单的办法是参考大厂

其实给项目定规范,最不靠谱的是自己拍脑袋,稍好一点的是去知乎或论坛问,更好一点的是去 google 搜,最简单的是直接去看大厂的产品或者规范啊。API 本来就是个公开暴露的东西,还有比这更好找参考的吗?我们来看看:

我的建议

很多人也许用着很简陋的 Web 框架,导致误以为返回了错误码,就不能返回 Response Body 了。其实你返回 204 外的任何 Status Code,最好都伴随着返回 Body。

在项目规范里,可以规定 Status Code 遵照 RFC 标准,或者选定一个集合出来,把一些不常用的去掉。然后如果不是 200 系列的代码,必须伴随着这样的一个错误结构:

{
    "error": "UserNotFound",
    "message": "该用户没有找到"
 }

这样错误分为了三层结构,第一层是 Status Code,使用者能大概知道是什么问题。第二层 Error 是一个 Key 使用约定好的无空格的英文,给使用者做判断用,使用者可以根据 Key 自定义接下来的操作。第三层是 message,有些 Key 使用者可以决定直接把 Message 显示个终端客户。

如果是微服务项目,需要要求每个服务不管用什么语言,都要把错误统一成这个样子。如果开发者告诉你框架不支持,那这一定不是个好框架,改重构了。好的框架不仅能让你自定义错误内容,还能做到所谓的“框架自己出错的返回”也由你自定义。比如路由没有找到之类的。

最后

我实在不明白为什么一个最扯淡的答案,要自造一个 600 的 status code,可以得票第一。知乎用户到底有没有一点独立的判断精神啊,只要装的一本正经,再摆出来一点资历,哪怕是胡说八道,大家也纷纷点赞。也许真的不适合在知乎去回答技术问题了。

7237 次点击
所在节点    编程
38 条回复
est
2019-02-22 14:26:04 +08:00
RESTful 过时了 REST-like 刚刚好。
loading
2019-02-22 14:27:34 +08:00
@est +1,落后的规范基本覆盖不了所有情况。
Muninn
2019-02-22 14:41:20 +08:00
@passerbytiny 同意你说的前半部分,ID 找不到的确有很多种可能。 这块因为因为这篇文章的知乎问题描述的很清楚,数据库里没有这条数据。所以这种情况下应该是 404 的。

否则根据情况可能是 400 401 403 404 410 都有可能。

但是你对于 500 的认识或许可以再去研究一下。500 的含义是表明这是一个未曾预料的问题。只有程序出 bug 了异常没有被处理,或者处理过程未预料的中断比如读数据库出错了的这些情况才会出现的。一个好的服务是不应该出现 500 的,出现了就可以肯定是服务方的错:)

场景二你描述的其实比较模糊,有可能是你觉的如果 id 是你提供的,客户端的请求肯定是对的,所以在程序里觉得如果找不到肯定是出现了未预料的状况,好了我认怂抛出个 500,要是出现了前端会找我,我再查查 bug。
但其实不存在这种状况的,因为 RESTful 你是不可控客户端的呀,说不定是前端同学拼 id 拼错了呢,调试的时候一看 500,锅直接就抛给你了。。。
mooncakejs
2019-02-22 15:04:57 +08:00
“ ID 找不到用不用 404 ”, 平时也是返回 404,但是每次回想起来都很别扭,实际上从主观出发还是支持找个 4xx 的状态码比较好。
rayhy
2019-02-22 16:21:53 +08:00
我个人也是按照楼主说的这样做的,但写项目的时候还是会遇到一些 http status code 不够用或者不够准确的情况,不知道楼主针对这些情况是怎么处理的?除了 http status code 之外,再增加一个 error code?
Muninn
2019-02-22 16:53:43 +08:00
@rayhy 看“我的建议” 那一节。

只要是错误,一定要自定义一个统一的错误结构体。可以返回第二级的 error code (可以是数字或者字符串),和 message。

我贴的微软的链接和下边有人贴的 paypal 的链接,也可以参考。不过有些过于复杂了,属于特别理想化的错误返回。
我和那些理想化的规范的核心不同是,我只考虑返回单个错误,而他们考虑了返回多个错误的情况。

多个错误又有链式的过程中出现的错误和列表处理中出现的并列错误两种情况。

实际上太复杂了为写程序造成负担,还是只返回一个最直接的错误好操作一些。
sparkle2015
2019-02-22 18:17:34 +08:00
@pubby

> 个人比较讨厌 restful
> 全部 post,全部 200

-----

那你可以尝试一下 GraphQL
AlisaDestiny
2019-02-22 19:56:24 +08:00
资源未找到用 404 的话会有歧义,到底是资源不存在还是 URL 不存在?
同意#6 说的 PayPal 规范:
Range Meaning
2xx Successful execution. It is possible for a method execution to succeed in several ways. This status code specifies which way it succeeded.
4xx Usually these are problems with the request, the data in the request, invalid authentication or authorization, etc. In most cases the client can modify their request and resubmit.
5xx Server error: The server was not able to execute the method due to site outage or software defect. 5xx range status codes SHOULD NOT be utilized for validation or logical error handling.
akira
2019-02-22 20:55:43 +08:00
公司内部只要约定好 用不用 404 都可以吧
ydirel
2019-02-22 22:49:26 +08:00
要遵守规范,status code 都有标准规定含义的。不然就会和标准冲突。
dengshen
2019-02-22 22:55:40 +08:00
神烦后台某个字段为空时连字段都不返回
例如正常数据
{name:xxx ",id:1}
实际数据
{id:1}

美其名曰:节约带宽!
johnniang
2019-02-22 23:32:55 +08:00
@AlisaDestiny 这个问题很好解决。

如果是 URL 不存在,将只会得到 status = 404 ;

若是资源未找到,不仅仅是 status = 404,而且还会返回一个错误 body,其中 errorcode = 404。

方能区分之。
Muninn
2019-02-23 09:37:11 +08:00
@AlisaDestiny 可以看看我帖子中 “我的建议”章节。

然后 paypal 和 microsoft 之类的 API 规范里也有类似的处理方案。
xfriday
2019-02-23 12:11:07 +08:00
可以在 http header 里添加自定义字段比如 My-Status: 1004,这样可以避免和常规状态码冲突或者不够用的情况
xfriday
2019-02-23 12:14:09 +08:00
在 http response body 里定义自定义状态(json/xml),无法处理字节数据,比如图片,到时候还是要退回到 http status code 来做业务判断
vibbow
2019-02-23 16:02:38 +08:00
<amp-youtube data-videoid="nSKp2StlS6s" layout="responsive" width="480" height="270"></amp-youtube>
Muninn
2019-02-23 21:26:41 +08:00
@vibbow 哈哈这是怨念有多深
Muninn
2019-02-23 21:42:12 +08:00
@xfriday 额外信息放在 Header 中也是个流派,但是这不是 Resp Body 的替代品。

首先,一般开发中图片都用的对象存储+CDN。

好,我们来考虑自己生成非文本对象的情况。

其实在 Response Body 中放 Error 结构体本质上就是正确返回和错误返回是不同的结构体,在客户端也会进入不同的处理流程。所以这跟正常结果是 JSON 还是 Object 没关系,错误了始终是一个错误结构体。

反而是全 200 流,一般才把错误放在 Resp body 中,导致如果正常返回不是一个 JSON 就没办法做了……
你又找到了一个全 200 流的缺陷。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/537513

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX