V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Vimax
V2EX  ›  Java

RESTful 的增删改查成功应该返回什么状态码?

  •  
  •   Vimax · 2020-07-14 15:13:54 +08:00 · 10906 次点击
    这是一个创建于 1625 天前的主题,其中的信息可能已经有所发展或是发生改变。

    RESTful 的 GET POST PUT DELETE 如果操作成功应该返回什么状态码呢?

    用 200,201,202,204 代表 4 种请求的成功合适吗?

    请求成功

    • GET 200 OK
    • POST 201 Created
    • PUT 202 Accepted
    • DELETE 204 No Content

    如果 GET POST PUT   DETELE 请求,数据库执行结果都为 0.又如何返回 HTTP 状态码呢?

    是返回 404 not found 吗?

    另外一个问题

    请求方式的数据类型: GET 和 DELETE 是否[不能]或[不推荐]使用 JSON 数据的形式.

    前端使用的是 VUE axios 发送请求,之前 DELETE 发送 JSON 数据,后端无法接收到.

    目前 4 种请求方式对应使用的数据类型是:

    • GET application/x-www-form-urlencoded
    • POST [ "application/json;charset=UTF-8" ]
    • PUT [ "application/json;charset=UTF-8" ]
    • DELETE application/x-www-form-urlencoded
    132 条回复    2020-07-16 10:37:35 +08:00
    1  2  
    hantsy
        1
    hantsy  
       2020-07-14 15:33:58 +08:00   ❤️ 1
    Spring 内容协商规律:

    Get , Accept: application/json
    POST,PUT Content-Type:application/json
    DELETE 不用管。

    实现:
    https://github.com/hantsy/spring-reactive-jwt-sample/blob/master/src/main/java/com/example/demo/web/PostController.java

    各种情况状态返回参考测试代码:

    https://github.com/hantsy/spring-reactive-jwt-sample/blob/master/src/test/java/com/example/demo/IntegrationTests.java
    qdzzyb
        2
    qdzzyb  
       2020-07-14 15:34:23 +08:00
    成功统一 200 就可以了
    Vimax
        3
    Vimax  
    OP
       2020-07-14 15:46:15 +08:00
    @hantsy 学习了.谢谢兄弟.
    Vimax
        4
    Vimax  
    OP
       2020-07-14 15:46:46 +08:00
    @qdzzyb 这样语义不清晰吧.
    bxb100
        5
    bxb100  
       2020-07-14 15:49:16 +08:00
    @Vimax #4 统一返回 200, 然后返回定义的 业务 code 处理错误
    chendy
        6
    chendy  
       2020-07-14 15:52:25 +08:00
    get 和 delete 默认没 body,指定 application/x-www-form-urlencoded 没用
    hantsy
        7
    hantsy  
       2020-07-14 15:53:22 +08:00
    在 Spring 3 。x 的时候都是要自己配置,现在自动内置了 Content Negotiation 内容。

    https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/

    对于 REST API,内容协商主要就是根据 Accept (返回内容可接受的格式) 和 Content-Type (请求的内容使用格式) 来决定 mediatype 。

    一般情况下:

    GET, 前端需要设置 Accept: application/json
    POST,PUT 前端需要设置 Content-Type:application/json
    DELETE 不用管。

    如果有特例,特殊要求,比如 POST 有返回内容,那么 Accept,Content-Type,甚至你可以用不同的格式。

    Accept:applicaiton/xml
    Content-Type:applicaiton/json

    这个依赖你后端是否能够处理。
    baiyi
        8
    baiyi  
       2020-07-14 16:01:33 +08:00   ❤️ 2
    状态码是根据不同的接口有不同的响应。

    GET 200 不必多说。

    POST 也有很多种形式,如果是正常创建并需要返回创建结果的,可以使用 201 Created
    如果是异步处理,提前响应结果的,需要使用 202 Accepted
    如果是正常处理,不需要响应结果的,需要响应 204 No Content
    如果是正常处理,但结果不方便直接响应,需要返回 205 Reset Content,提示 Client 重新获取

    如果你想写一个非常标准的 HTTP API,那就需要学习每个状态码所代表的含义,不能与请求方法一一对应
    如果不想这么费劲,因为确实也没多少人在乎,那就完全可以直接 200,也没问题
    hantsy
        9
    hantsy  
       2020-07-14 16:03:16 +08:00
    对于 Accept,Content-Type,Spring 的 Controller 方法 @RequestMapping (或者其它 GetMapping,xxx 等) 可以设置 produces,consumes 属性对应处理。

    Accept ---------------produces
    Content-Type----------consumes

    默认情况下,现在 Spring 处理过于宽松,什么格式都放进来。严格的情况下最好指定 Mediatype,对于一些不支持格式,前端访问 API 时,Spring 会更快速的响应,返回 415 。
    jones2000
        10
    jones2000  
       2020-07-14 16:38:22 +08:00
    你返回数据结构里面应该有一个状态码, 这些查询或操作失败的, 最好是返回 200 ok, 然后内有有一个状态码来表示具体的错误码,好点的还有一个错误的描述字符串, 方便前端提示给客户,否则都是 404,客户直接抓瞎了。
    hantsy
        11
    hantsy  
       2020-07-14 17:39:57 +08:00
    @jones2000 404 怎么会抓狂???

    /posts/anoneexistingpost 是一个不存在的 Post
    /users/noneexistignuser 是一个不存在的 User
    /products/noneexiting 是一个不存在的产品
    /orders/noneexiting 是一个不存在的订单
    hantsy
        12
    hantsy  
       2020-07-14 17:41:58 +08:00   ❤️ 2
    不同的路径下 404 的意义已经将不同的 Resource 区分的很清楚,只有 SB 才用 200 返回一切数据。
    wangyanrui
        13
    wangyanrui  
       2020-07-14 17:44:46 +08:00
    全部 200,自定义 code

    另:前面的兄弟们吵起来不要带上我~
    zhuweiyou
        14
    zhuweiyou  
       2020-07-14 17:48:21 +08:00   ❤️ 2
    国情是全部 200,你搞各种状态码,前端要骂你的。
    qdzzyb
        15
    qdzzyb  
       2020-07-14 18:03:32 +08:00
    @Vimax #4 不会不清晰吧 GET 200 POST 200 PUT 200 DELETE 200 这四个表示的是四个语义吧
    一般前端喜欢 统一返回 200 body 里{code: 0, data: xxx} 或者 {code: xxx, err_msg: "error message"}
    EminemW
        16
    EminemW  
       2020-07-14 18:08:41 +08:00 via iPhone
    不是应该 http 状态码描述请求状态 自定义业务状态码描述业务状态么
    hantsy
        17
    hantsy  
       2020-07-14 18:28:40 +08:00
    @qdzzyb
    @zhuweiyou 你们公司由前端决定系统架构吗?由前端来定交互协议?
    hantsy
        18
    hantsy  
       2020-07-14 18:39:24 +08:00
    Angular 中 httpclient 处理 API 使用 Rxjs Obseverable, subscribe 中 next 和 error 天然分开处理。

    用 axios 访问 API 的话,then 里面正常业务,catch 处理异常。

    代码清楚可见。

    全部返回 200 就会部跑到 then 里面, 代码变成屎一样。哪个前端喜欢写这样的屎?我听到很多前端抱怨过后端写的什么垃圾都塞进 200 body,自己拿到还要先判断。

    自己的懒惰,无知和无能非要说成什么国情,前端需要。
    wanacry
        19
    wanacry  
       2020-07-14 18:39:57 +08:00 via iPhone
    参考 es 的
    xlinux
        20
    xlinux  
       2020-07-14 18:41:41 +08:00 via Android
    400 会不会被打?
    pwli
        21
    pwli  
       2020-07-14 18:44:10 +08:00 via Android
    如果要上监控和重试的话,失败请求不建议返回 200
    hantsy
        22
    hantsy  
       2020-07-14 18:47:37 +08:00
    @xlinux https://www.restapitutorial.com/httpstatuscodes.html 这个页面标星基本都是最常用的。4xx 系列之前项目还用到
    422 Unprocessable Entity (WebDAV) 输入验证异常用上了这个。
    402 Payment Required

    405,406,415 这种基本都是非法调用,框架会提示你。
    ChanKc
        23
    ChanKc  
       2020-07-14 18:49:52 +08:00
    @pwli 是的,我最近打算上一些日志分析就发现。
    如果一些错误用 400,直接打 access_log 里面,然后用标准的 access_log 分析工具分析就能看到一些数据
    要是都是 200,还要造一堆轮子
    ChanKc
        24
    ChanKc  
       2020-07-14 18:54:57 +08:00
    @qdzzyb 我作为前端,很不喜欢统一 200
    如果用 axios,我要自己封装 Promise 异常
    如果用 service worker 做缓存,我 fetch 完了还要把 body 用 json()拿出来判断一下才能决定要不要缓存
    qdzzyb
        25
    qdzzyb  
       2020-07-14 18:58:31 +08:00
    @ChanKc #24 其实我也不喜欢都返回 200 尽量能用状态码就用状态码
    hantsy
        26
    hantsy  
       2020-07-14 18:58:50 +08:00
    @ChanKc 除了 ELK, EFK 之类的,可以看看现在的云服务,PagerDuty, DataDog 之类。
    qdzzyb
        27
    qdzzyb  
       2020-07-14 19:00:43 +08:00
    @hantsy #17 前面开发的大佬用了这一套,前端也都封装好了
    bigWolf999
        28
    bigWolf999  
       2020-07-14 19:01:19 +08:00
    还有一个问题,数据量大且结构复杂的请求数据是否只能将 GET 改为 POST 呢?
    labulaka521
        29
    labulaka521  
       2020-07-14 19:02:09 +08:00
    习惯就好,上面那个说别人 SB 才是个大 SB
    passerbytiny
        30
    passerbytiny  
       2020-07-14 19:03:42 +08:00 via Android
    不想细分就 200,想细分就 20*,*具体是哪个前面有人回复过了。

    成功统一 200 ( OK ),错误统一 500 (服务器内部错误),也是符合 RESTful 的,只不过 500 太多显得服务器很无能。


    至于“全部 200”这样的回复,劝一句楼主,不要跟闭眼抄作业的人玩。
    happypy1
        31
    happypy1  
       2020-07-14 19:59:35 +08:00
    如果你的 GET 是来搜索的话,即使你没有找到数据,你应该返回 200 OK,因为 200 意味着你的搜索请求,服务器执行成功了。而且像这种搜索 endpoint 的话,你应该是返回一个空的数组,如果没有找到资源的话。

    但是如果你的 GET 是要拿一个具体的资源的话,比方说你知道 ID:GET /custoemrs/1,后端要是没有找到,就应该返回 404 。否则就返回 200 。

    202 一般是用于表示后台已经接受了你的数据,但是还没有处理完成。参考一下[MDN]( https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202)

    如果你只是简单的创建或者更新数据的话,200 即可。
    xuanbg
        32
    xuanbg  
       2020-07-14 20:00:12 +08:00
    @passerbytiny 全部 200 的意思是只要服务能够正常访问就返回 200 。http 的状态和业务的错误分开。
    daimubai
        33
    daimubai  
       2020-07-14 20:08:29 +08:00   ❤️ 1
    我们项目:
    请求成功统一 200
    客户端错误统一 400
    服务端错误统一 500
    系统异常错误—999
    hantsy
        34
    hantsy  
       2020-07-14 20:48:24 +08:00
    @labulaka521 神经病
    renmu123
        35
    renmu123  
       2020-07-14 20:50:24 +08:00 via Android
    v2 周经贴
    hantsy
        36
    hantsy  
       2020-07-14 21:00:08 +08:00
    @bigWolf999 有些 API 有一个专有的 _search endpoint,比如 /products/_search,可以看看 MS API 设计(被 REST 之父喷过),还包括各种比较,逻辑操作等,太复杂了,query params 表达不了,这种 POST 方便。
    hantsy
        37
    hantsy  
       2020-07-14 21:02:19 +08:00
    @qdzzyb 后端 java Spring,我之前也见过这种神封装,好好的 ResponseEntity 带个套,所有的 Controller,所有方法返回用一个 Util 套一下。
    labulaka521
        38
    labulaka521  
       2020-07-14 21:07:29 +08:00 via iPhone   ❤️ 2
    @hantsy nmsl
    hantsy
        39
    hantsy  
       2020-07-14 21:14:38 +08:00
    @labulaka521 就你这样,我真替你父母感到悲哀。
    在工作中,你就是我说那种人,狗屁正事做不了,借口比谁都多的巨婴,整个公司估计也没人待见你。
    jones2000
        40
    jones2000  
       2020-07-15 00:52:50 +08:00
    @hantsy “不同的路径下 404 的意义已经将不同的 Resource 区分的很清楚,只有 SB 才用 200 返回一切数据” 你这种方式我没看到过,太高级了, 我还不会用,特别是如何把 sql 的执行错误的详细信息如何返回给前端然后提示客户。

    数据库执行错误就几十种, 主键冲突, 表不存在,账号没有写权限等等,还要具体错误信息。

    像以下的详细的错误应该如何通过你的 404 返回给前端
    1. “ALTER TABLE `xxxx_db`.`STOCK2604` DROP PRIMARY KEY
    Can't DROP 'PRIMARY'; check that column/key exists”

    2. “ALTER TABLE`xxxx_db`.`STOCK2604`ADD PRIMARY KEY(`ORGID`,`SECCODE`,`ENDDATE`,`F001V`,`F004V`)
    Specified key was too long; max key length is 767 bytes”

    3. “SELECT CAST(CONV(HEX(MAX(`XDBMASK`)),16,10)AS UNSIGNED),CAST(CONV(HEX(MIN(`XDBMASK`)),16,10)AS UNSIGNED)
    FROM`xxxxxx` WHERE CAST(CONV(HEX(`XDBMASK`),16,10)>0
    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 2”
    newtype0092
        41
    newtype0092  
       2020-07-15 01:03:36 +08:00
    @jones2000 别问,问就是需求不合理。
    什么样的需求才叫合理?只提标准 RESTful 能直接实现的需求,其他的不做就完事了。
    你看 XX 大厂 RESTful 都能满足需求,你们需求还能比人家复杂?

    可以和同行讨论观点,不要和教徒争论信仰。
    jones2000
        42
    jones2000  
       2020-07-15 01:22:24 +08:00
    @newtype0092 谁发我工资 谁的需求就合理。 我只是打工的, 只会具体到一个一个需求的实现才能拿工资糊口。太空泛的概念对我没什么用, 还是要能实现具体需求才行呀。哪有直接对老板说你的需求不合理,不做。现在工作不好找难呀。
    lihongming
        43
    lihongming  
       2020-07-15 02:42:44 +08:00 via iPhone
    全用 http code 做状态码是一种理想,实际很难做到,因为你总会有一些非标准的或是需要细分的状态。

    所以还是 http 的归 http,业务的归业务就好,不要被那些鼓吹纯 http code 的人吓到,须知任何事情走向极端都是邪教。更何况很多大公司的 API 也在这么做(比如 amazon ),你不是一个人!
    hantsy
        44
    hantsy  
       2020-07-15 08:13:20 +08:00
    @jones2000 如果我没记错的话,V 站几乎都是 Spring 。Spring 的 ExceptionTranslator 会将所有的所有的数据库异常翻译成相应的 DataAcessException (子类),而在 Spring Boot 中所有的内置的异常 Spring 已经处理了。

    数据库异常问题,这类的系统问题根本就不应该丢给前端,常识,自己从项目一开始就要有自己的日志分析处理系统,监控日志。

    再说了,你的这些例子就是程序错误,你们不写测试吗?
    IvanLi127
        45
    IvanLi127  
       2020-07-15 08:18:57 +08:00 via Android
    @zhuweiyou #14 那是掉队的野生前端吧
    crclz
        46
    crclz  
       2020-07-15 08:19:26 +08:00
    200:成功
    401:Unauthorized 未登录
    403:Forbidden 没权限操作资源
    404:NotFound,一是由框架在无法匹配路由时抛出,二是当 PATCH or DELETE /article/{id}时 id 找不到的时候返回。
    400:其他错误情况。这个里面要自己设计数据结构以便细分,例如{code: UsernameNotFound, message: 用户名不存在}
    hantsy
        47
    hantsy  
       2020-07-15 08:27:21 +08:00
    Amazon 最新一代的 API 还没完成(没完全覆盖所有业务),上一代(现在通行)基于十几年的开发结果,不必细说。Http Status 处理,Github API 是典范,Github 返回的异常结果也有业务 code,但是仅针对 Httpstatus 表达不了的状态,作一个补充,现在 Github 也提供了新的 GraphQL 。
    hantsy
        48
    hantsy  
       2020-07-15 08:31:31 +08:00
    @crclz 这个还不错。

    尽可能利用 HttpStatus,比如用户注册,Email 已经存在,返回 Conflict 状态 ,这种表达更直接。POST 数据验证 Validation 失败,可以用 Unprocessable Entity,这些状态的字面意义才是对错误异常的说明起到真正辅助作用。
    hantsy
        49
    hantsy  
       2020-07-15 08:33:17 +08:00
    hantsy
        50
    hantsy  
       2020-07-15 08:40:18 +08:00
    我不懂的是这些状态的字面意义这么清晰的情况下,完全抛弃不用,还要定义自己所谓的业务码,返回 200,把整个系统代码(前后端)搞成一锅粥。业务参考码我也会用一些,但会参考 Github,仅仅在一些通用错误下作补充说明,比如一些 400 太不清晰,其它的能用 HttpCode 一律不用业务码。

    国内,这几年仅仅在上海做过两个创业项目,也是严格按我第一帖子的状态来写的,老板好像不会管你用什么方法解决,所以写成这样,公司老板是不应该背锅的。
    hantsy
        51
    hantsy  
       2020-07-15 08:44:19 +08:00
    结帖。
    oneisall8955
        52
    oneisall8955  
       2020-07-15 09:01:42 +08:00 via Android
    去年某段时间的周经贴
    ragnaroks
        53
    ragnaroks  
       2020-07-15 09:09:47 +08:00
    草,只有我用自定义状态码?
    yaphets666
        54
    yaphets666  
       2020-07-15 09:40:45 +08:00
    统一返回 200 是最好了 你返回其他的状态码 有些状态码都到不了 js 里 直接被浏览器处理了 200 是前人实践出来的
    matenshi
        55
    matenshi  
       2020-07-15 09:55:23 +08:00
    成功就 20x (不过不会像主楼说的那样区分), 不成功看情况,40x,500 之类的(并返回错误信息)
    Airon
        56
    Airon  
       2020-07-15 10:13:12 +08:00
    成功 20x 错误 40x, 后端业务错误 500,具体业务错误 {code:, message: } 。基于工作环境的水平吧,大类错误码大家知道自带含义,那它就能起到辅助作用。
    cruii
        57
    cruii  
       2020-07-15 10:39:07 +08:00
    全部返回 200,结果后端出错封装一个自定义错误码。
    这种就很让人不舒服,HTTP 规范告诉我请求成功了,结果后端告诉我请求出错了。
    binux
        58
    binux  
       2020-07-15 10:55:34 +08:00   ❤️ 2
    @yaphets666 不会可以闭嘴
    akira
        59
    akira  
       2020-07-15 11:19:33 +08:00
    @cruii 应该是指成功返回 200, 不成功的返回才使用别的
    yaphets666
        60
    yaphets666  
       2020-07-15 11:21:01 +08:00
    @binux 小伙子年轻吧 没遇到过运营商劫持非 200 返回的情况吧 你不知道别人为啥都 200 你最好别自己找自己的路 跟着别人走也许不太对 但绝对不至于出什么大事
    binux
        61
    binux  
       2020-07-15 11:25:18 +08:00
    @yaphets666 “直接被浏览器处理了”???
    还有现在还不上 https 的公司就别呆了。
    libook
        62
    libook  
       2020-07-15 11:30:20 +08:00
    HTTP 是通信协议,建议将协议上的状态与业务上的状态分开,所以 HTTP 的返回状态码最好严格按照 HTTP 标准来使用,涉及到业务状态的最好在返回结果里用额外的状态标识来标识。

    比如 DELETE,服务器执行成功,且返回 Body 有内容,则返回 HTTP 状态码 200 (其他情况参考 2xx 段各个状态码的定义),返回的 Body 里用字段或对象来体现业务上的状态,是有记录且成功删除了,还是成功执行了但无可删除记录,还是删除错误 1 、删除错误 2 等等。
    4xx 段在标准中表示的是因客户端错误导致的非预期的请求,这就看你如何定义这个 API 了,比如 API 的 URI 被视为一个确定的资源,如 /user/12345,那么业务上可以定义为使用 DELETE 方法是建立在 ID 为 12345 的这个 user 资源存在的基础上的,那么 HTTP 协议上可以首先考虑这个资源是否存在,如果不存在的话,业务上可以认为这个资源不存在客户端就不应该发出这个请求,就按照 HTTP 标准返回 404,告诉客户端它发出的这个请求有问题。

    这些都不是固定死的,关键是一套系统的 API 应该有统一的一套自己的标准。
    比如你定义除了创建以外,任何对于资源的直接操作都应该基于资源存在的基础,资源不存在一律返回 404 状态。
    然后系统内所有 API 都按照这个标准来设计就可以了。
    REST 只是一套帮助你设计自己系统 API 标准的思想,最终还是要为业务服务的,如果其思想与业务需求相矛盾,就没必要硬上 REST 风格。
    wangyzj
        63
    wangyzj  
       2020-07-15 11:32:01 +08:00
    200
    libook
        64
    libook  
       2020-07-15 11:37:52 +08:00
    可能写得有点长,核心没表达清楚。

    返回 404 是因为“需要告诉客户端它犯了个(请求的资源不存在的)错误”,而不是因为“这个资源不存在”;同样的,返回 200 是因为“需要告诉客户端这个请求成功了(且不属于其他 2xx 状态码的情况)”,而不是因为“业务成功了”。

    可以细细品一下。
    baiyi
        65
    baiyi  
       2020-07-15 11:38:31 +08:00
    @bigWolf999 #28 query 过多且过于复杂时,可以使用查询语言类协议,比如 GraphQL
    RJH
        66
    RJH  
       2020-07-15 15:03:12 +08:00
    直接 200,然后在响应体里面返回定义业务状态码,不懂就参考微信、阿里的接口
    zsdroid
        67
    zsdroid  
       2020-07-15 15:14:40 +08:00
    别人来讨论问题,总有一些人以为自己很牛逼,一上来就喷。别人反喷他一下,他就急了。
    zsdroid
        68
    zsdroid  
       2020-07-15 15:19:42 +08:00
    iugo
        69
    iugo  
       2020-07-15 15:27:27 +08:00
    @libook

    - 需要告诉客户端它犯了个(请求的资源不存在的)错误
    - 这个资源不存在

    我觉得这两个难以区分.

    我认为我理解你想要表达的, 就是协议统统 200, 不需要 404, 除非 API 路由都不对, 才会 404.

    但这种设计不符合 RESTful, 这里不是说 RESTful 绝对正确, 而是不符合 RESTful.
    iugo
        70
    iugo  
       2020-07-15 15:29:36 +08:00
    如果把 HTTP 状态码当作后端错误代码的分类, 这样似乎就很好理解.

    我是不建议弃用 HTTP 状态码, 只用 200 的.
    frankwei777
        71
    frankwei777  
       2020-07-15 15:44:04 +08:00
    我前端 成功只见过 200
    markliu2013
        72
    markliu2013  
       2020-07-15 15:44:15 +08:00
    @hantsy

    /posts/anoneexistingpost 是一个不存在的 Post
    /users/noneexistignuser 是一个不存在的 User
    /products/noneexiting 是一个不存在的产品
    /orders/noneexiting 是一个不存在的订单

    这种返回 404 是最佳实践吗?我觉得 404 是告诉客户端,他请求的接口不存在,但是 /posts/这个接口是存在。比如本来一个 user 资源是存在的,但是被另一个用户删除了,这时候在请求就会 404,客户端就会感觉莫名其妙。

    比如在一个 MVC 的架构里面,请求 users.php?id=1,但是 id 为 1 的 user 不存在,这时候能返回 404 吗?
    hantsy
        73
    hantsy  
       2020-07-15 15:53:04 +08:00
    @markliu2013

    /posts/<id 或者 id 对等物,比如 Slug>, 如果这个 ID 不存在,返回 404, 这个意思。你还在武汉?微信或者邮件聊吧。
    hantsy
        74
    hantsy  
       2020-07-15 15:57:57 +08:00
    @markliu2013 或者你看直接代码吧。
    markliu2013
        75
    markliu2013  
       2020-07-15 16:01:41 +08:00
    技术问题就这里聊聊吧。
    我的意思是 404 在这里是否是最佳实践的设计。因为这个接口本身是存在的,也去数据库查询了,但是查询结果是空集合。

    我找到了这个问题:
    https://stackoverflow.com/questions/11746894/what-is-the-proper-rest-response-code-for-a-valid-request-but-an-empty-data
    目前有说 404,但是也有说用 204 或者 200
    hantsy
        76
    hantsy  
       2020-07-15 16:02:12 +08:00
    >404 Not Found: The requested resource could not be found but may be available again in the future.

    就是表示你访问的时候资源不存在。
    hantsy
        77
    hantsy  
       2020-07-15 16:04:51 +08:00
    @markliu2013 你说的 Users.php? 的情况是集合,永远返回 200,即使是空的 Body,除非有其它逻辑出玩异常要处理。

    posts/:id 表示单个资源。
    hantsy
        78
    hantsy  
       2020-07-15 16:06:28 +08:00
    目前我所用的 404 都是会定位到单个资源上操作上 get, put, delete,找不到的时候都返回 404 。
    hantsy
        79
    hantsy  
       2020-07-15 16:10:33 +08:00
    集合查询结果为空用 204 感觉有点牵强,用 json 的话,它是一个空的数据 [] ,这个内容长度不是 0 。
    zsdroid
        80
    zsdroid  
       2020-07-15 16:18:45 +08:00
    @cruii HTTP 规范告诉你请求成功了,结果后端告诉你业务出错了。没毛病吧。
    难道实际上请求成功了,却告诉你请求失败了才对?
    est
        81
    est  
       2020-07-15 16:22:52 +08:00
    @hantsy 呵呵。订单 200 表示存在,404 表示不存在,那已拆分订单如何表示?

    硬用 4 个动词+几个有限的状态码去套真实世界的业务模型才是 sb 。
    zsdroid
        82
    zsdroid  
       2020-07-15 16:25:05 +08:00
    2014 年,某网友:其实所谓的 restful 更适合那些总想着沽名钓誉的硕士研究生们去堆砌辞藻,用来体现出自己比其他众多工程技术人员“高人一等”。
    一开始以为其只是个喷子,对其所说不以为然,一笑而过。
    如今看来,这位网友说的太对了。就像某位“大佬”一样,restful 确实可以高人一等。
    zsdroid
        83
    zsdroid  
       2020-07-15 16:26:32 +08:00
    hantsy
        84
    hantsy  
       2020-07-15 16:30:07 +08:00
    我突然发现定制 HTTP 标准定制者,REST 之父 Fielding 博士都不如你们。
    @zsdroid
    @est
    hantsy
        85
    hantsy  
       2020-07-15 16:31:30 +08:00
    在你们的世界,只要一个请求方法,一个状态,所有问题都可以解决,全世界做技术都是 SB 。
    markliu2013
        86
    markliu2013  
       2020-07-15 16:34:37 +08:00
    @hantsy REST 给安卓和 iOS 端使用,有啥问题吗?
    RoyceLee
        87
    RoyceLee  
       2020-07-15 16:35:10 +08:00
    话都不要说满了,历史的滚滚车轮会告诉我们,当时认为是对的,可能是大错特错的。
    hantsy
        88
    hantsy  
       2020-07-15 16:41:03 +08:00
    @markliu2013 没有问题。

    但是如果移动端原生开发,可以选择其它协议,不一定要用 REST 。

    RSocket 直接用 TCP,原生效率更高。
    WebSocket ( web,Android 原生都是可以用),这个我以前做过一个聊天游戏的后端。

    当然我以前是主张混合使用,实时用 WebSocket 交互,一般用 REST 。
    libook
        89
    libook  
       2020-07-15 16:42:00 +08:00
    @iugo

    - 告诉客户端它犯了个错误
    - 业务上这个资源不存在

    把括号里的去掉可能更突出重点? HTTP 4xx 状态表示“Client Error”,所以主要是突出客户端犯了错误,即客户端在当前情况下不应该发送这个请求。
    如果你认为当前客户端发这个请求完全合理,在预期正常的情况下,那么就返回 2xx 。

    我没有说“协议统统 200,不需要 404”,事实上你返回 200 还是返回 404 都是可以的( REST 根本就没定义应该返回什么,它也完全不 care ),完全取决于你是否认为这个情况是客户端的错误;关键是系统上所有接口得统一起来,哪些情况一律返回 200,哪些情况一律返回 404.

    REST 只是个风格,而不是标准。
    [Roy Thomas Fielding 博士的论文]( https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)第 5 章描述了究竟什么是 REST 风格,但是篇幅非常短,即便是第 6 章的实践部分也没有详细介绍 REST 的最佳实践。
    论文前面章节提到了 API 设计的一些问题,而 REST 本身就是为了解决这些问题而提出的思路而已,只要是按照这种思路去设计 API,就是 RESTful 的,就能享受到 REST 带来的收益。

    如果认为一种设计违背 Roy Thomas Fielding 博士对 REST 风格的定义,可以引用论文里的段落来说明。

    当然如果把某企业或某项目的 REST 实践当做标准的话,就没有什么可讨论的了。
    est
        90
    est  
       2020-07-15 16:43:51 +08:00
    @hantsy Fielding 这货在 Adobe 最自鸣得意的发明是 Coldfusion 。也没见你来天天吹呢?
    libook
        91
    libook  
       2020-07-15 16:44:29 +08:00   ❤️ 1
    忘了这不能用 markdown 语法。。。

    Roy Thomas Fielding 博士的论文
    https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
    est
        92
    est  
       2020-07-15 16:46:25 +08:00
    其实 Fielding 发明 RESTful 有一个极其狭窄的用途,那就是最老派的 HTTP 资源。什么是资源?就是文件。所以 RESTful 最成功的应用应该是 WebDAV 。这跟 Coldfusion 的设计也是一脉相承的。然而现代 web 早就进化得连妈都不认识了。你们还抱着 CGI 时代的老掉牙概念到处吹 B 。

    以我的觉得,读操作走 GET,写操作走 POST,其余放在 JSON 里拉倒。
    xuanbg
        93
    xuanbg  
       2020-07-15 16:48:31 +08:00
    @binux 这个和 https 没关系,你可以尝试以移动 APP 或者服务间调用的角度来看这个事情。因为业务层逻辑不想也不应该关心传输层的事情,是的,除了 web 外,其他调用者使用 http(s)协议只是为了传数据而已。如果不同情况下返回的数据类型不统一,处理起来就很麻烦。所以才有只要请求正常,就是 200 这种方案。
    对于 web 来说,可以很方便处理 http status,不同的 status 比较优雅。但对于其他端来说,这就是灾难。
    hantsy
        94
    hantsy  
       2020-07-15 16:54:02 +08:00
    @libook Richardson Mature Model 具体的可用于 REST 设计的指导性原则。

    https://martinfowler.com/articles/richardsonMaturityModel.html

    Fielding 那个博士论文主要讲一些 REST 特性。
    lbunderway
        95
    lbunderway  
       2020-07-15 17:03:07 +08:00
    我们也是统一 200 再由业务 code 区分 哈哈
    hantsy
        96
    hantsy  
       2020-07-15 17:17:03 +08:00
    恰好我用过 Allaire Jrun,所以我知道 CodeFusion 也是 Allaire,但我没有用过。后来( 20 年前左右) Allaire 被 Macromedia 收购。CodeFusion,Jrun 这些服务器都是被边缘化。

    到了后来,Adobe 并购 Macromedia,早就没有这些产品。

    请问 Fielding 是怎么跑到 Adobe 公司去做 CodeFusion 产品???
    @est
    maigebaoer
        97
    maigebaoer  
       2020-07-15 17:18:54 +08:00 via Android
    所有都是 200,加一个返回码。反正我受不鸟这种,但是公司要用。
    est
        98
    est  
       2020-07-15 17:24:37 +08:00
    > 请问 Fielding 是怎么跑到 Adobe 公司去做 CodeFusion 产品???

    @hantsy 这个我就不知道了。毕竟 adobe 里只有 ColdFusion 没有 CodeFusion 。
    takemeaway
        99
    takemeaway  
       2020-07-15 17:27:50 +08:00
    老问题了,你想用什么就用什么,不能自由选择就按照公司给你的标准来。
    hantsy
        100
    hantsy  
       2020-07-15 17:30:26 +08:00
    @est 没错,这个你对了,我写错了,是 ColdFusion,一般简写 CF 。这个产品明明是 Allaire 的,那请问怎么变成 Fielding 在 Adobe 期间的得意作品。

    Adobe 并购 Macromedia 才几年而已。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1173 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 18:21 · PVG 02:21 · LAX 10:21 · JFK 13:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.