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

RESTful 有用吗? HTTP 有 GET POST 就足够了?

  •  
  •   noli · 2017-02-15 12:59:26 +08:00 · 40082 次点击
    这是一个创建于 2599 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不少程序员都是这么认为的,基于 HTTP API 的服务,只要用 GET 请求和 POST 请求就足够了。 像 RESTful 这样的 大量使用 PUT , DELETE 请求是不必要的。

    真的吗,我来举一个例子。

    假设有一类资源 ResourceXYZ ,对其有增删查改的操作。 如果只使用 GET POST 之类的设计方式,那么很可能会设计以下的请求接口:

    POST .../addResourceXYZ
    POST .../delResourceXYZ
    GET .../getResourceXYZ?resourceId=resourceId
    POST .../updateResourceXYZ
    

    如果按照 RESTful 的 设计方式,很可能会设计以下的请求接口

    POST .../ResourceXYZs
    DELETE .../ResourceXYZ/{resourceId}
    GET .../ResourceXYZ/{resourceId}
    PUT .../ResourceXYZ/{resourceId}
    

    现在假设,客户端要获取该资源,其 ID 为 resourceId 。 如果成功,那么一切都好说。 如果失败, Restful 的处理方式是,通过 HTTP status 返回错误码来表示原因,例如 404 表示该资源不存在。

    那么只用 GET POST 两种方法的方式呢? 响应请求

    GET .../getResourceXYZ?resourceId=resourceId
    

    的时候能不能也用 404 呢?

    按照 404 的语义,响应 404 是不对的: 因为客户端请求的 URL 实际上是正确的,只是对应的参数没有找到对应的结果 很多时候,就只能靠响应 200 然后返回空数据或者空对象来处理了。 例如 Content-type 为 application/json 时,可以返回 {} 或者

    {
        "error": "not found",
        "code": 404
    }
    

    这样就会要求客户端,必须处理 HTTP 回复的具体内容,而不能只处理头部。 那么客户端要怎么处理这个 json 呢 要先解析 json ,然后尝试分别这是一个资源的内容,还是一个错误提示。

    对于强类型语言例如 C/C++ OC Swift 写的客户端来说,恐怕就忍不住要问候服务端程序员一家了。

    更重要的是……

    没有库会支持这种拍脑袋式的设计。

    全文完,欢迎拍砖。

    207 条回复    2018-09-01 23:44:06 +08:00
    1  2  3  
    xgfan
        1
    xgfan  
       2017-02-15 13:08:28 +08:00   ❤️ 1
    问题在于,加上 delete 和 put 也是不够的。
    那些状态码也是不够的。
    wingoo
        2
    wingoo  
       2017-02-15 13:08:55 +08:00
    POST .../addResourceXYZ
    POST .../delResourceXYZ
    GET .../getResourceXYZ?resourceId=resourceId
    POST .../updateResourceXYZ

    ==============
    本身 api 端是按照模块划分的
    所以
    GET .../getResourceXYZ?resourceId=resourceId
    可以划分为
    GET .../getResource1
    GET .../getResource2

    restful 只不过帮你把这些定义自动划分好了而已
    另外返回值, 默认为 200
    正确,错误 会在返回代码里统一定义
    Reign
        3
    Reign  
       2017-02-15 13:11:42 +08:00   ❤️ 2
    其实,有 POST 就够了, GET 都是多余的
    m939594960
        4
    m939594960  
       2017-02-15 13:11:47 +08:00
    主要是状态码完全不够用,大部分都需要 先获取一下 header 判断是否正确,然后解析 json 判断 code 代码。、
    wingoo
        5
    wingoo  
       2017-02-15 13:13:57 +08:00
    至于前端调用解析结果, 这个不管是否使用 restful 都需要前端去判断
    而统一的结构只会有好处, 不会有坏处
    更何况, 错误还可以统一处理啊

    如果这种设计叫拍脑袋设计, 那你所接触的系统基本都是拍脑袋了
    奉劝下 lz 不要迷恋权威
    restful 只是 restful 而已
    cloudyplain
        6
    cloudyplain  
       2017-02-15 13:15:03 +08:00   ❤️ 1
    404 的例子理解不了,个人认为 restful 去掉了 url 中的动词",简化了 url 命名。
    miyuki
        7
    miyuki  
       2017-02-15 13:17:05 +08:00
    /t/336226 相关主题……
    laxenade
        8
    laxenade  
       2017-02-15 13:20:58 +08:00
    反正都不遵守 restful 了 为什么还要遵守 404 的语义。
    Matrixbirds
        9
    Matrixbirds  
       2017-02-15 13:29:38 +08:00
    按照 spec 的 rule ,认为 get 的请求是不会对服务端状态造成改变的。 post 则会改变
    noli
        10
    noli  
    OP
       2017-02-15 13:29:54 +08:00
    @xgfan 对于资源增删查改不够的话,请问要加上什么操作?能不能举个例子?

    @wingoo 你说的 GET .../getResource1 是只把 resourceId 作为后缀填到 URL 里面去吗?那这跟 RESTful 有什么区别?
    RESTful 不能统一处理吗?能否统一处理是后端架构的问题,跟 RESTful 无关。

    @laxenade RESTful 是 HTTP 之上的概念, 404 是 HTTP 的概念,不同层。如果 HTTP 语义都不遵守,确实没啥好说的。
    noli
        11
    noli  
    OP
       2017-02-15 13:34:42 +08:00
    @wingoo

    想向你补充一句:
    按照 RESTful 的设计来做不叫迷恋权威。
    而是不必自己另外发明一套轮子。
    undeflife
        12
    undeflife  
       2017-02-15 13:35:19 +08:00
    Sequencer
        13
    Sequencer  
       2017-02-15 13:35:20 +08:00 via iPhone
    在 header 里面鉴权…
    post 发 json 指令有啥不好的……
    clino
        14
    clino  
       2017-02-15 13:39:45 +08:00
    我也只用 get/post ,其他都没用
    noli
        15
    noli  
    OP
       2017-02-15 13:42:04 +08:00
    @cloudyplain
    URL 名称叫做 Universal Resource Location ,本来只是用来表明资源的位置。
    而加上动作前缀,也不是不可以,但这种方式偏离了表示资源位置的本意,耦合了其他语义。

    例如, getResource 返回 404 ,那么可以有两种方式理解:
    1. 不看动词,表明该资源不存在
    2. 看动词,表明 1 )不存在这种资源,或者 2 )不存在对这种资源的操作,或者 3 )资源存在但不支持这种操作
    magict4
        16
    magict4  
       2017-02-15 13:46:31 +08:00   ❤️ 2
    如果我有个 Email 的 Service , GET/PUT/DELETE/POST 分别对应增删查改,那『发送』,『存档』,『移到文件夹 X 』又该如何表示呢?
    gamexg
        17
    gamexg  
       2017-02-15 13:50:33 +08:00 via Android
    没意义, 404 时想要返回错误信息还是需要解析返回的内容结构。
    那直接 200 不一样吗?
    kenshinhu
        18
    kenshinhu  
       2017-02-15 13:51:29 +08:00
    我发现我一起用的是 假的 RESTful
    magict4
        19
    magict4  
       2017-02-15 13:52:41 +08:00
    我支持 @xgfan 说的。在逻辑比较复杂的业务场景里, Restful 提供的 4 个动词是远远不够的。
    noli
        20
    noli  
    OP
       2017-02-15 13:54:52 +08:00
    @magict4

    如果将 Email 视作 Resource ,或者更广泛地考虑,用 RESTful 来描述 IM 消息:
    向某人发送消息,应该是在 其消息队列中 POST 一个新资源, 用
    ```
    POST /{SomeBody}/messages/
    ```
    存档某消息,其实也就是同样的意思

    移到文件夹 X 这里面略坑,因为包括两个步骤: 1. 在新位置复制一个 2. 在旧位置删除
    看需要是否做成事务式的:
    如果是事务式的,应该是事务队列增加一个资源

    如果不是事务式的,那么分别执行 POST 和 DELETE
    noli
        21
    noli  
    OP
       2017-02-15 13:56:48 +08:00
    @gamexg

    如果不需要解析错误信息呢? RESTful 能够照顾到两种需求。
    如果直接返回 200 做不到这一点。
    magict4
        22
    magict4  
       2017-02-15 14:05:20 +08:00
    @noli 我不会这么设计我的 API 的。 Messages 这个概念,是因为 Restful 只提供了 4 个动词的一种变通。我的 Server 可能通过 Message Queue 来实现消息的传递,但这种底层的东西不应该暴露给我的客户。我需要暴露给客户的,应该是类似 send email, archive email, move email 之类的接口东西,然而这并不能通过 Restulful 来直接实现。你可参考下 AWS 的服务文档
    Felldeadbird
        23
    Felldeadbird  
       2017-02-15 14:08:59 +08:00
    我个人认为 GPPD 最重要的优点在于 统一了 URL 操作,节省了起名的困难。
    例如:现在 CURD 都是 /article/1.html 。 我都不用去想起他动作了。
    换以前,/article/1.html , /addarticle/1.html, /updatearticle/1, /removearticle/1..
    murmur
        24
    murmur  
       2017-02-15 14:11:43 +08:00
    以现在的框架 restful 更多成为一种形式或者信仰 除了 json 发出和 json 结果比较讨人喜欢 其余的没啥问题
    比如 /api/removeItem 和 /api/item 发 del 有什么区别么?前者如果命名一致文档合理同样是优秀设计
    noli
        25
    noli  
    OP
       2017-02-15 14:12:25 +08:00
    @magict4

    我说的 Messages 是类似于论坛消息之类的业务 Message , Email 概念的泛化、抽象化。
    你当然可以不用 Restful 来实现,而且我本人也不建议。
    你要我举个例子,那我就免为其难了。

    事实上,我认为,操作系统的全部 系统调用,都可以用 RESTful API 来对应表示。
    不习惯的人可能会觉得别扭,但是是可行的、科学的、经得起考验的。
    noli
        26
    noli  
    OP
       2017-02-15 14:13:28 +08:00
    @murmur

    "比如 /api/removeItem 和 /api/item 发 del 有什么区别么?"

    见 #15
    wshcdr
        27
    wshcdr  
       2017-02-15 14:14:07 +08:00
    我认为采用 restful 的话, 客户端(包括移动端)是要自己维护自己的业务接口的,服务端只是暴露 GET/PUT/DELETE/POST 分别对应增删查改

    对应发邮件的例子,也就是客户端要自己实现发送这种功能,自己在发送功能里协调对 GET/PUT/DELETE/POST 的调用。
    mcfog
        28
    mcfog  
       2017-02-15 14:17:46 +08:00   ❤️ 3
    1. restful 是风格不是规范
    2. 如果楼主如果真心认为“ POST /updateXYZ?id={id}”和“ PUT /XYZ/{id}”对等,那我觉得并不能说是真正理解了 restful
    3. 正如其他很多同学说的, restful 的状态码数量有限,用于表示复杂的业务问题经常不够,基本最终还是要在 body 里定义自己的错误描述体系
    4. restful ,状态, cookie , session 之间的关系我一直没找到权威说明。业界常见的 restful 风格接口大多用非 cookie 的令牌 token+服务端 session 来处理状态,此时接口连基本的在 web 端和 app 复用都得讨论了( token 让 js 自己存储和 secure httpOnly 的 cookie 的安全性差距)欢迎指教
    5. 把接口分两大块:
    a) 业务接口( app/web 等使用的),这类接口我倾向全 POST 或幂等读 GET 其他 POST ,返回结构统一 code,message,body 的风格, HTTP 状态码用来表述“通信状态”, body 内返回吗表述“业务状态”
    b) 后端接口( CGI 端再调其他 server 用的),这类接口如果业务逻辑量小,贴近“资源 CRUD ”的 restful 最贴切的领域的话,我会考虑 restful 作为备选方案
    magict4
        29
    magict4  
       2017-02-15 14:22:17 +08:00
    @noli 你看看我有没有误解你的意思。拿『移动到文件夹 X 』举例。

    如果是事务的,我猜你对应的 URL 会是
    post .../MoveEmailTransaction

    如果不是事务的,你说会用两个 HTTP request 来实现,那对应的 URL 肯定跟上面的会有所不同。

    如果我的理解是对的话,同样的一件事情,因为实现不同,对应的接口变了。在我看来,好的 API 设计应该是无论实现怎样, API 应该保持稳定。所以我会用
    post .../moveEmail?source=???&&destination=???

    > 但是是可行的、科学的、经得起考验的
    如果因为实现的不同,需要改变 API 的设计,我不太能认同是科学的。

    我的主要观点是, Restuful 提供的 4 个动词是远远不够的。在复杂的业务场景里面,如果想用这 4 个动词来表示所有操作,往往会让 API 的设计变的更加困难。
    baiyi
        30
    baiyi  
       2017-02-15 14:22:35 +08:00   ❤️ 1
    RESTful 说到底也只是众多 Api 规范 中的其中之一, 它是有一定的适用性的.

    在 RESTful 适用性之外的项目,就不要强行上 RESTful 了

    现在 Api 的规范都和语言之争一样火爆了......
    baiyi
        31
    baiyi  
       2017-02-15 14:24:05 +08:00
    @baiyi 口误,RESTful 是设计风格不是设计规范
    otakustay
        32
    otakustay  
       2017-02-15 14:34:31 +08:00
    restful 是架构风格,不是接口设计风格,如果你做不到 restful 架构,请不要在接口这么个东西上盲目追求 restful
    gevin
        33
    gevin  
       2017-02-15 14:37:52 +08:00   ❤️ 1
    又想提一下我原来写的两篇博客:

    RESTful 架构风格概述: http://blog.igevin.info/posts/restful-architecture-in-general/
    RESTful API 编写指南: http://blog.igevin.info/posts/restful-api-get-started-to-write/
    noli
        34
    noli  
    OP
       2017-02-15 14:41:37 +08:00
    @magict4

    在一个 openstack 相关的业务里面,我用 RESTful 实现过对 AD ( ActiveDirectory )相关的接口 WEB 封装。
    里面也是经常有对各种简单的、原子的 对各种 AD 条目的操作的 组合所形成的事务。
    提交事务方法只有一种:
    ```
    POST .../Transaction
    ```
    然后在请求体里面用 JSON 描述这个事务的各种操作和参数,例如:

    ```
    {
    [
    {"method": "POST", "resource": "/someResources", "args": {...} },
    {"method": "DELETE", "resource": "/someResource/1234"},
    ]
    }
    ```
    实际上就是把一连串的 RESTful API 调用转化成一个 JSON 对象来描述要执行的事务。

    所以你说“同样的一件事情,因为实现不同,对应的接口变了” 实际上不存在~ :)
    zweite
        35
    zweite  
       2017-02-15 14:47:31 +08:00
    想象当 Restful 遇到爬虫会怎么样
    msg7086
        36
    msg7086  
       2017-02-15 14:50:06 +08:00
    为了去套 RESTful 而强行把不是资源或者不适合以资源形式访问的东西也当做资源,就是个问题了。
    这有点像数据库的范式,你可以把范式堆得老高,但是实际开发中没人会真的这么干,意思意思做得干净点就行了。
    顺便提一句,很多实现里(比如浏览器), HTTP 动词是只支持 GET/POST 的, PUT/DELETE 都要用 _method=? 之类的来传递,然后在上层去抽象。
    baiyi
        37
    baiyi  
       2017-02-15 14:50:08 +08:00
    @zweite RESTful 跟爬虫关系不大, 因为他返回较为完整的 http 信息,或许对爬虫更加友好
    whx20202
        38
    whx20202  
       2017-02-15 14:51:58 +08:00
    @otakustay 我一直以为是接口设计风格。

    给你这么一说我才反应过来 肯定有很多接口看起来 restful 实际后端架构并不是
    baiyi
        39
    baiyi  
       2017-02-15 14:52:04 +08:00   ❤️ 1
    http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
    这篇文章是我看来关于 Api 中 RESTful 的实践 中最好的一篇文章了

    想要更深的了解 REST,可以去找找博士的论文读
    wizardoz
        40
    wizardoz  
       2017-02-15 14:55:43 +08:00   ❤️ 2
    非要说够不够的,那我说一个 POST 就够了,还要 GET 干啥?
    所以我们要的不是够,我们要的是优雅。
    fucker
        41
    fucker  
       2017-02-15 14:59:55 +08:00
    POST .../ResourceXYZ?action=delete/add/update
    kulove
        42
    kulove  
       2017-02-15 15:01:58 +08:00 via iPhone
    风格而已,没必要完全遵守
    noli
        43
    noli  
    OP
       2017-02-15 15:08:41 +08:00
    @wizardoz 说得太好了。要的就是优雅。

    那些说 RESTful 是 风格而不是规范的同志们,扯这个没用。
    你看看各大平台下的各种 RESTful 相关的库,你就知道什么是风格什么是规范了。
    遵守这个风格也好,规范也好,就提供一种使用开源代码的机会。
    不遵守也不是不行,自己掌握细节,然后实际上是把 RESTful 的规范用另外一种形式实践一遍。
    neutrino
        44
    neutrino  
       2017-02-15 15:08:55 +08:00
    即使是资源的 CRUD ,也不推荐用 Restful 。 HTTP 状态应当仅由 HTTP 服务器处理,如 404 是指没有找到处理的程序,而不是程序处理了发现资源没找到。任何经处理的结果应当一律以 HTTP 200 返回,表示这是一次成功的 HTTP 请求,并在 body 中表示请求的结果。
    noli
        45
    noli  
    OP
       2017-02-15 15:14:31 +08:00
    @neutrino

    只使用 HTTP 200 , Content-type 都是 JSON
    缓存服务器要怎么判断返回的是成功处理的结果,还是出错提示?
    neutrino
        46
    neutrino  
       2017-02-15 15:34:58 +08:00
    @noli 对于动态处理的内容不应当缓存,不推荐 urlrewrite ,每一个 url 都应当是实际存在的文件,仅缓存静态文件。应当显式暴露入口文件。
    Balthild
        47
    Balthild  
       2017-02-15 15:43:28 +08:00
    @noli 说得对啊,只是要优雅罢了。如果不用 REST 比用 REST 更优雅,那为什么要用 REST 呢?
    hxtheone
        48
    hxtheone  
       2017-02-15 15:45:25 +08:00
    请求方式表示行为, URL 表示资源, 个人表示很喜欢, 在 URL 里带上动词总是感觉太啰嗦了点
    noli
        49
    noli  
    OP
       2017-02-15 15:49:48 +08:00
    @neutrino

    “动态处理的内容不应当缓存”? 明明基于 HTTP 动作、状态码和特定 HTTP 头就能实现的事情,硬生生因为你非要返回 200 而自废武功。

    “每一个 url 都应当是实际存在的文件” —— HTTP 3XX 也可以不用了是吧?

    所以你这是把规范的实现的效果,在写代码的时候实践了一遍
    还不如老老实实遵守全套的 RESTful 规范呢
    noli
        50
    noli  
    OP
       2017-02-15 15:51:12 +08:00
    @Balthild

    请举一个 HTTP 上更优雅的设计风格。
    PhilC
        51
    PhilC  
       2017-02-15 15:55:56 +08:00
    ```
    POST .../Transaction
    ```
    然后在请求体里面用 JSON 描述这个事务的各种操作和参数,例如:

    ```
    {
    [
    {"method": "POST", "resource": "/someResources", "args": {...} },
    {"method": "DELETE", "resource": "/someResource/1234"},
    ]
    }
    ```
    你这个是 restful ?
    hronro
        52
    hronro  
       2017-02-15 15:55:56 +08:00
    所以讲道理,最终还是 GraphQL 最好😂
    menc
        53
    menc  
       2017-02-15 16:00:05 +08:00
    逻辑不对啊, 404 , 403 状态码是针对 URL 的,不是针对动作的,它只能标识该 URL 的相关信息,不能用状态吗来作为后端逻辑执行结果的证明。
    lxrmido
        54
    lxrmido  
       2017-02-15 16:00:24 +08:00
    你说得很有道理,假如我是三十年前的程序员我一定支持你。
    noli
        55
    noli  
    OP
       2017-02-15 16:00:43 +08:00
    @PhilC 里面的 JSON 是手打的,确实是格式不对。
    但 POST 一个 JSON 有什么问题么? 为什么觉得不是 RESTful ?
    noli
        56
    noli  
    OP
       2017-02-15 16:07:16 +08:00
    @menc

    https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6

    The Status-Code element is a 3-digit integer result code of the attempt to understand and satisfy the request

    所以并不是只针对 URL 的。
    事实上 HTTP 405 Method Not Allowed 就是针对你的说法的反例。
    PhilC
        57
    PhilC  
       2017-02-15 16:10:12 +08:00
    ```
    {
    [
    {"method": "TEST", "resource": "/someResource/1234"},
    ]
    }
    ```
    我 POST 一条这样的 JSON ,你是不是也要返回 HTTP 405 Method Not Allowed
    rogerchen
        58
    rogerchen  
       2017-02-15 16:15:48 +08:00
    以前是绝对路径 / 后边是 CGI ,?后边是传给 CGI 的参数。
    restful 把参数写在路径里,搞万物都是 URI ,方法作为动作参数。

    我个人觉得就是两种不一样的范式, restful 主要搞 CRUD 这种比较简单的东西, CGI 更适合搞参数比较复杂的系统。
    rogerchen
        59
    rogerchen  
       2017-02-15 16:18:08 +08:00
    @noli URL 确实是 locate 资源的, CGI 不过是 locate 到了一个脚本。
    baiyi
        60
    baiyi  
       2017-02-15 16:23:45 +08:00
    @hronro GraphQL 有什么可学习的资料吗?
    noli
        61
    noli  
    OP
       2017-02-15 16:24:59 +08:00
    @PhilC

    在我那个实现里面, POST Transaction 的时候大多数情况下返回 200 以及事务 ID
    然后根据 事务 ID 查询 事务状态的时候,会给出事务的状态、结果什么的。

    当然,这个设计是有不足之处的,例如 事务里面的前后两条如果有输出间的依赖关系的话,目前是实现不了的。
    但是,你举的这个例子也太 TM 弱智了吧……?
    hronro
        62
    hronro  
       2017-02-15 16:38:59 +08:00   ❤️ 1
    undeflife
        63
    undeflife  
       2017-02-15 17:01:12 +08:00
    @magict4 后几个都可以用 patch 因为是修改状态
    Sight4
        64
    Sight4  
       2017-02-15 17:02:26 +08:00   ❤️ 1
    这个 topic 在 V2EX 已经引战 N 次...

    1. 在经历多个前后端分离的坑之后,从结果上看,完全符合的 restful 规范风格的 api 是很难实现(应该说是实现起来反而很别扭)

    2. 但是 restful 风格的 URL 、幂等性、授权对于设计基于 web 的 api 是很有指导意义的,所以最终在项目实施的时候,很多时候都会按照资源来划分 url ,但是不再使用 http 返回码以及 method 来表达资源的结果和用途,毕竟, API 文档还是要写的嘛

    3. 其实,统一的 http post 在某种意义上很方便前端对 api 的封装
    chairuosen
        65
    chairuosen  
       2017-02-15 17:06:30 +08:00
    又来引战了
    noli
        66
    noli  
    OP
       2017-02-15 17:10:03 +08:00
    @msg7086

    漏了回复你。
    对于某些浏览器不支持 GET POST 之外的动作,可以用 http method override
    baiyi
        67
    baiyi  
       2017-02-15 17:37:36 +08:00
    @Sight4
    @chairuosen

    虽说我也认为楼主有点引战的意思.
    但是,这类的"战争"我觉得还是有一定意义的.
    能引得起来,就说明还是存在着许多人不认同的地方,有了更多的讨论,融会贯通嘛,对自身的理解也很有帮助
    noli
        68
    noli  
    OP
       2017-02-15 17:39:44 +08:00
    @Sight4

    1. 因为很多人根本没有操刀设计 API 的水平。别说 RESTful 了,我厂也算知名互联网企业,某 C++ SDK 出品一样是个渣渣。 RESTful 要考虑的更多难度更高,但说 RESTful 会导致实现别扭…… 呵呵

    2. HTTP 返回码和 回复里面的返回码,通常其含义不应该是冲突的,诸如 HTTP 200 但是 "code": 404 这种只能说某些人自以为很了解 HTTP 协议及其客户端。


    3. 不用 HTTP method ,那么基本上就是把动作写在 URL 里面,这种设计我觉得见仁见智,有些时候是很省事,但通常深挖一下就会发现是解耦不够。
    更重要的是,这基本上等于放弃了各种 RESTful client SDK 带来的好处。
    那还不如直接点干脆不用 HTTP

    所以我觉得你说了很多没有经过深入思考的经验,但基本上是废话。
    guokeke
        69
    guokeke  
       2017-02-15 17:41:36 +08:00 via Android
    restful 已死。 graphql 当立。
    Sight4
        70
    Sight4  
       2017-02-15 18:10:58 +08:00 via iPhone   ❤️ 1
    @baiyi 唉,主要是每次引战,非得要说那个是适合,那个不适合,抛开场景来啥扯一般很难有结论, restful 优雅,但 db 设计的三范式何尝不是?度是很重要
    cnt2ex
        71
    cnt2ex  
       2017-02-15 18:20:12 +08:00
    URL 不是 Uniform Resource Locator 吗?
    Actrace
        72
    Actrace  
       2017-02-15 18:30:25 +08:00
    猩球大战开始了。
    Lucups
        73
    Lucups  
       2017-02-15 18:42:56 +08:00
    同样的话题这已经是我看到过的第 4 篇 topic 了。

    看到现在的评论,我的感觉是大多数人倾向于:
    restful 不错,有借鉴意义,但我只会有限使用或者在不会去用。
    lightening
        74
    lightening  
       2017-02-15 18:52:29 +08:00
    @magict4 仔细想的话,其实都是对资源的操作。

    发送是 CREATE 了一个 delivery ,移动和归档是 UPDATE 了状态(或位置,取决于你的实现)。我倒不是觉得做 API 应该永远按照 RESTful 设计,但确实仔细想想的话,确实至今我没有遇到任何不能 fit 进 REST 的操作。

    推荐 DHH 的关于 RESTful 的演讲:
    jsq2627
        75
    jsq2627  
       2017-02-15 20:13:22 +08:00
    restful 是信仰,不是一言两语能说清楚的。
    https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md
    pathbox
        76
    pathbox  
       2017-02-15 21:31:41 +08:00
    怎么会没有人用呢
    zhengkai
        77
    zhengkai  
       2017-02-15 21:36:35 +08:00
    忘了 RESTful 吧,去了解 GraphQL
    zonyitoo
        78
    zonyitoo  
       2017-02-15 23:25:55 +08:00
    其实 GET 也是多余的,只需要 POST
    Balthild
        79
    Balthild  
       2017-02-16 01:06:52 +08:00
    @noli 别转移话题,我说的不是什么东西比 REST 更优雅,我说的是在不用 REST 更优雅的前提下就不要用 REST 。
    请求的东西不是资源时, REST 一点都不优雅。
    noli
        80
    noli  
    OP
       2017-02-16 01:50:21 +08:00
    @Balthild

    你要说优雅,那你优雅的标准是什么?举个例子都没有,我很难跟你说话哦。

    又说请求的东西不是资源,什么东西不能视作资源来被管理呢?除了无限的东西之外。

    你没有办法用合适的方式把要管理的东西视作资源
    ——我见到的很多程序员都这样,例如楼上某层不知道事务怎么用资源视觉来处理——
    就说 RESTful 不优雅,这是拒绝承认自己有问题。
    magict4
        81
    magict4  
       2017-02-16 05:22:20 +08:00
    @lightening 我暂时还没开看你贴的视频,有时间的话会看。

    如果我没有理解错,你跟楼主的意思应该都是

    sendEmail 对应的是 createDelivery
    moveEmail 对应的是 createTransaction

    之所以会有这样的对应,是因为 Restuful 只提供了 4 个动词。有了这样的限制,我们不得不对资源名字进行变换,把 email 变成 delivery 和 transaction 。

    我同意你说的,我们总是可以想办法把 API fit 进 Rest 这个框架 /风格。但是我不能认同我们应该这样做。
    TigerS
        82
    TigerS  
       2017-02-16 06:55:05 +08:00
    小网站感觉完全够用,但是如果稍微大点就不太方便。

    例如 DigitalOcean API ,我们自己写一个小的管理的时候基本上是
    ```
    api_url: 'https://api.digitalocean.com/v2/'
    def action(action, droplet_id):
    blah_blah(api_url + 'droplet_id' + action)
    ```
    只是举例,随便写了点

    很多东西都可以调用,而且简单易懂,而且很多可以重复利用

    但是如果全是 post 的话,就需要不断确认是 post 到了哪里,虽说也可以,但是有时候并不好用。
    baconrad
        83
    baconrad  
       2017-02-16 10:46:57 +08:00
    以前端來看,今天我使用

    `GET .../ResourceXYZ/{resourceId}`

    結果 server 回傳 HTTP status 404

    請問以下哪個原因才是正確的?

    1. client 端網路環境出問題。
    2. server 端網路環境出問題。
    3. url 輸入錯誤。
    4. 我要求的資源不存在。
    ShiningRay
        84
    ShiningRay  
       2017-02-16 10:47:26 +08:00
    你说的是以 RPC 的风格来设计 API
    另外楼主肯定用了很麻烦的对 restful 不友好的框架
    mqtt
        85
    mqtt  
       2017-02-16 11:46:07 +08:00
    POST .../addResourceXYZ
    POST .../delResourceXYZ
    GET .../getResourceXYZ?resourceId=resourceId
    POST .../updateResourceXYZ

    这样的命名我是无法接受的,又长又丑。
    资源不存在, 本来就应该提示 404 啊, 表明用户访问的资源未找到,这样客户端就可以通过 response code 知道自己请求的资源不存在。
    mqtt
        86
    mqtt  
       2017-02-16 11:46:46 +08:00
    response status
    changwei
        87
    changwei  
       2017-02-16 11:50:25 +08:00 via Android
    这种争论可以直接参考大公司的最佳实践。

    你们去看一下大公司的 app 接口就知道了,像百度腾讯的 app 接口都只有 get 和 post ,然后返回的 json 里面有专门的错误码,错误消息解释和消息体。
    baiyi
        88
    baiyi  
       2017-02-16 12:33:02 +08:00
    @changwei github 大吗
    baiyi
        89
    baiyi  
       2017-02-16 12:34:12 +08:00
    @changwei github 不光有 RESTful 的, 还有 GraphQL 的
    国内的公司没有, 只能说明他们不去接触新东西,或业务不合适,代表不了其他的什么
    jybox
        90
    jybox  
       2017-02-16 12:43:17 +08:00
    其实我的想法和楼主差不多(两年多以前我也在 V2EX 发过类似的帖子),即我是觉得 RESTful 并不能覆盖到所有的情况,硬要把不适合的业务对应到「资源」是个费力不讨好的事情。但确实如果能够顺着 RESTful 的思路的话,会有一些比较方便的工具可用,所以也没有必要非要「不遵守」 RESTful 。所以我觉得在做 API 设计的时候,最重要的是项目本身能够统一和自恰,适合 RESTful 的部分就用,不适合的情况也没必要硬往上靠。

    RESTful 和 HTTP 本身的关系并没有那么密切,关于如何设计基于 HTTP 的 API 实际上不止 RESTful 一个方案。
    loading
        91
    loading  
       2017-02-16 12:44:07 +08:00 via Android
    只是参考,用 get,put,post,dekete 对于我来说就是可以少写几个路由。
    noli
        92
    noli  
    OP
       2017-02-16 13:53:22 +08:00 via iPhone
    @baconrad

    1 和 2 是不可能的因为服务器已经返回 404 了所以肯定网络没有问题

    3 和 4 都有可能
    noli
        93
    noli  
    OP
       2017-02-16 13:56:55 +08:00 via iPhone
    @ShiningRay

    猜错了,第一版后端是我写的, restful 很爽。现在我主攻客户端,后端业务升级给了另外一个人,所以我才会集中吐槽不用 restful 会给客户端带来多大的麻烦?
    wizardforcel
        94
    wizardforcel  
       2017-02-16 14:08:16 +08:00
    动态路由不等于 REST ,非 REST 也可以用动态路由 GET /ResourceXYZ/{resourceId}。

    别什么都往 REST 上套。
    TangMonk
        95
    TangMonk  
       2017-02-16 14:11:34 +08:00
    @Reign GET 可以 cache 。。
    wizardforcel
        96
    wizardforcel  
       2017-02-16 14:16:07 +08:00
    以及。。很多 http 客户端库不支持除了 get 和 post 之外的方法,遇到这种情况我真是。。。

    另外不用 REST 照样也可以设计出来优雅的路由

    增: POST /ResourceXYZ/create
    删: GET /ResourceXYZ/{resourceId}/delete
    改: POST /ResourceXYZ/update
    查: GET /ResourceXYZ/{resourceId}
    noli
        97
    noli  
    OP
       2017-02-16 14:29:18 +08:00 via iPhone
    @magict4

    我觉得设计 restful api 的时候很重要的一点是,要弄清楚业务理念哪些概念是原子性的,哪些操作是可以通过多个对原子性概念的操作组合出来的。

    如果你觉得让客户端来做这些原子性动作组合,是要求太高,那么你可以加一层 api 来接收客户端的意图,然后在这层 api 之下实现业务,

    这样通常能解决很多所谓 fit 进 restful 的问题
    wizardforcel
        98
    wizardforcel  
       2017-02-16 14:30:09 +08:00
    @noli

    > 又说请求的东西不是资源,什么东西不能视作资源来被管理呢?除了无限的东西之外。

    如果不用 REST ,某些 API 我就可以设计成

    /login
    /reg
    /tranfer

    用了 REST 就没有这些简明扼要的设计,这是不是增加复杂度呢??
    wizardforcel
        99
    wizardforcel  
       2017-02-16 14:33:27 +08:00
    @noli

    > 如果你觉得让客户端来做这些原子性动作组合,是要求太高,那么你可以加一层 api 来接收客户端的意图,然后在这层 api 之下实现业务,

    客户端做原子性动作组合存在安全隐患。

    服务端里增加一层 API 嘛。。为什么我要在 HTTP API 里面调用 HTTP API ,而不是直接调用 DAO 或者 ORM 呢??没你这么抽象的。 HTTP API 就不是给服务端自己调用的,这样粒度比 DAO 大多了。
    noli
        100
    noli  
    OP
       2017-02-16 14:44:59 +08:00
    @wizardforcel

    /login /reg /transfer
    你能用这种方式设计这些 api ,恰好说明了你的业务不需要把这些行为视作资源。
    如果你需要满足这些需求的时候,你就自然要用 restful 了

    1. 查询某用户在某时段内的 login 记录
    2. 针对某些注册申请进行人工审核,或者拒绝或者 forward
    3. transfer 是异步的,需要实时关注 transfer 是否完成

    你没有这些需求,你当然不需要把这些视作资源。

    关于“为什么要在 HTTP API 里面调用 HTTP API ”
    没有为什么,我不关心实现,因为这只是为了适应低能的客户端,怎么实现是业务需要问题。
    至于为什么 HTTP API 调用 HTTP API ,那是因为 do not repeat your self. 当这些被调用的 更底层 API 实现有变动的时候,你不需要改高层 API 的实现,虽然这也不一定是必须的。
    你连这个道理都不懂,我感觉我们的层次有差距啊。
    1  2  3  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3808 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 10:20 · PVG 18:20 · LAX 03:20 · JFK 06:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.