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

我是一个人么,还有人觉得 RESTful 是糟糕的设计么。

  •  
  •   jybox ·
    jysperm · 2014-05-09 14:54:45 +08:00 · 13110 次点击
    这是一个创建于 3853 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我主要写后端代码,以前写 PHP, 现在写 Node.js. 刚听说 RESTful 的时候,觉得很高端大气上档次,很理想很美好。但在后来的实践中发现 RESTful 很大程度上拖慢了后端的开发速度,而对前端(AngularJS)的开发速度改善也很有限。

    RESTful 希望将所有请求都包装成对资源的新增,读取,修改,以对应不同的 HTTP 动词,但是并非所有请求都可以归到前面几类,既然无法将所有请求都 RESTful 化,甚至无法将大部分的请求 RESTful 化,那么意义就很有限了,会导致花费大量时间斟酌 API 应该如何设计。

    RESTful 将一部分参数放到了 URL 里,还有一部分参数在 Header 里,从 URL 和 Header 里分离参数,虽然有库的辅助,但是我觉得很麻烦。

    RESTful 通过 Status Code 来表示结果状态,但是通常的情况下,结果只有成功和出错两种情况,出错的情况分很多种,原因都很复杂,即使有 Status Code 依然需要有一个字符串来描述错误详情,所以 Status Code 在这里就显得很多余了。

    所以我现在开始坚定地黑 RESTful, 我认为「传统」的 API 设计才是最可行的,即:

    * URL 是一个动词,其中不包含参数。
    * 没有副作用的请求可以用 GET, 其余必须 POST
    * POST 时用正文传递参数,GET 时用 Query String 传递参数
    * Status Code 为 200 或 400, 后者会返回一个字符串形式的错误代号。
    39 条回复    2015-06-17 16:30:59 +08:00
    robertlyc
        1
    robertlyc  
       2014-05-09 15:00:40 +08:00
    先把Roy Fielding的博士论文读懂
    ddyy
        2
    ddyy  
       2014-05-09 15:03:18 +08:00
    同样的道理也可以用在“面向对象”、“设计模式”、“TDD开发”上,理想很美好,但现实需求很凌乱,让这些看上去很美的“模式”套不上
    hepin1989
        3
    hepin1989  
       2014-05-09 15:06:32 +08:00
    怎么容易怎么弄,爱咋地咋地
    robertlyc
        4
    robertlyc  
       2014-05-09 15:17:53 +08:00   ❤️ 4
    难怪 原来是php程序员
    binux
        5
    binux  
       2014-05-09 15:20:01 +08:00   ❤️ 6
    - RESTful 是一种思想,但它没有规定所有的事情,一只装备了 RESTful 的猴子并不能设计 API
    - 参数在URL中和在 header 中的语意是不一样的,对应后端的处理路径也不一样,这样拆分是有意义的
    - status code 是对出错类型的分类简化,用户可以在不知道具体出错原因的情况下,根据类型采取不同的动作,例如对于 400 是客户的错,500 的原因是服务器的问题,并进行重试。status code 的错误归纳是标准化非常有价值的设计。
    cloudzhou
        6
    cloudzhou  
       2014-05-09 15:38:34 +08:00   ❤️ 8
    一一回应:
    1 get, post, put, delete 方法的细化,可以很容易在上层做权限拦截,从读取,新建,修改,删除层次上就做到了,当然这个是对方法的使用比较严格。
    对于一般的资源,比如 /v1/user/1/ (几个方法表示获取,创建,修改,删除),如果用你现在的方法,那要怎么表示,无论如何都会很冗余。
    rest 是为了描述通用资源的管理,如果你抽象得好,绝大多数请求都是可以归类出来的。其他的你可以自行实现,比如你说的「传统」的 API 设计...
    2 从 URL 和 Header 里分离参数是有特别意义的,比如 https://developer.github.com/v3/#authentication,用户认证的 Token 必须放到 Header,如果你放在 URL 里,这是一种不安全的方法。总之,敏感信息是不能带在 URL 上面的,类似 Token,sessionid,Header 是最好的选择。
    3 Status Code的细分,你看看下面的描述,你觉得这些没有用的?
    200: 正常,可能附带数据
    201: 需要创建的对象已经存在
    400: 请求参数或者格式不对
    403: 没有相关的权限
    404: 资源没有找到
    500: 内部数据出现错误

    总结:
    大部分的麻烦,要考虑是不是代码写得不对,因为 rest 的这种规范,代码其实更好写的,以 java 为例子,非常好做继承和复用,统一的错误和异常处理,比如一旦 403 转到权限不足提示页面。
    unstop
        7
    unstop  
       2014-05-09 15:47:48 +08:00
    @binux @cloudzhou 感谢二位的答案,很有帮助!
    iwege
        8
    iwege  
       2014-05-09 16:15:44 +08:00   ❤️ 4
    > "但在后来的实践中发现 RESTful 很大程度上拖慢了后端的开发速度,而对前端(AngularJS)的开发速度改善也很有限。"

    主要的原因是你没用framework... nodejs是因为express本身非常轻量级所以很多需要自己配置。换做Laravel,CakePHP或者ROR,开发速度是杠杠的..


    > "甚至无法将大部分的请求 RESTful 化,那么意义就很有限了,会导致花费大量时间斟酌 API 应该如何设计。"

    1. 你尚未真正明白RESTful的意义。
    2. API的设计是很花费时间的,除非直接抄,否则推到两三次都是正常的。如果不需要设计API还不如直接后端render好了.
    3. 如果你觉得RESTful不够好,你可以考虑SOAP

    “所以我现在开始坚定地黑 RESTful”

    一般来说,坚定的黑你就要一直不使用他的理念:
    http://www.infoq.com/cn/articles/understanding-restful-style

    以上文章里面提到的你要坚决的一点都不用的话,应该才算是坚定的黑.

    PS. 翻了楼主的帖子发现《王垠又接着写博客了》的那张贴,顿时明白了前辈们的智慧是如此的闪耀...
    learnshare
        9
    learnshare  
       2014-05-09 16:19:01 +08:00   ❤️ 2
    @cloudzhou +10086

    1. RESTful 是为了将数据/资源抽象化,形成统一的方法(GET/PUT/PUST/DELETE),方便前(or 客户端)后端进行 API 的规范化。
    2. header/params/data 的功能不同,这个应该是属于 HTTP 协议部分吧,我不是很了解。
    3. 状态码是一种规范,或者叫标准。现在应该大部分人都知道 404 了,这就是标准带来的好处。

    如果你的程序没有达到一定规模,使用 RESTful 可能真的是多余。

    如果你的程序需要(或者将来可能需要):
    1. 稳定健壮可扩展;
    2. 支持不同终端/客户端访问(Web、App 或 其他程序调用);
    3. 有其他人来接手/参与...

    建议使用 RESTful
    airyland
        10
    airyland  
       2014-05-09 16:22:58 +08:00   ❤️ 2
    虽然楼主觉得理解透了而且也实践了,但是还是建议再去看看别人的设计别人的实现 。
    “拖慢开发速度“这不是RESTful的问题,是你们开发上的问题。
    learnshare
        11
    learnshare  
       2014-05-09 16:27:51 +08:00
    @unstop
    >如果不需要设计API还不如直接后端render好了.

    我司的另一个技术领导一直坚持后端 render,其实也未尝不可。

    具体采用什么,还要看自己是不是熟悉。不过在深入了解一门技术之前,先别 **扣帽子** 。
    lyd600lty
        12
    lyd600lty  
       2014-05-09 16:28:04 +08:00
    满足需求,开发顺畅,用不用RESTFUL都可以啊。
    bolasblack
        13
    bolasblack  
       2014-05-09 16:37:24 +08:00
    @lyd600lty 确实用不用都可以,只是如果接受这个风格的话,那么其实是能够提升开发效率的。就像 @lwege 说的一样,你发现突然出现了很多工具来帮助你完成你的工作,而且你也能找到很多的实践和方法来解决你遇到的问题
    learnshare
        14
    learnshare  
       2014-05-09 16:38:48 +08:00
    #11 at 错了,sorry :)
    binux
        15
    binux  
       2014-05-09 16:38:53 +08:00
    @lyd600lty 当你要和别人解释你的 API 的时候,RESTful 会帮你省去很多口水
    lyd600lty
        16
    lyd600lty  
       2014-05-09 16:41:08 +08:00
    @binux 确实是这样,不过我曾经跟楼主纠结这个问题的时候,我也费了很多口水- - ~
    soli
        17
    soli  
       2014-05-09 16:54:32 +08:00   ❤️ 1
    HTTP status ranges in a nutshell:

    1xx: hold on
    2xx: here you go
    3xx: go away
    4xx: you fu*ked up
    5xx: I fu*ked up
    justfindu
        18
    justfindu  
       2014-05-09 16:58:24 +08:00
    @robertlyc 能别黑php程序员么 碍着你了么~ 只有你用的语言才是高大上,好又多么~
    alsotang
        19
    alsotang  
       2014-05-09 16:59:47 +08:00
    restful 跟 sql 的 crud 配合得很好。
    楼主什么场景?
    mfaner
        20
    mfaner  
       2014-05-09 17:41:57 +08:00
    REST才是HTTP的本意。
    用过WebDAV没?你会发现HTTP是多赞的协议。
    Wuvist
        21
    Wuvist  
       2014-05-09 18:02:42 +08:00
    你不是一个人,我就很讨厌restful,万物皆resource就跟OOP万物皆对象一样。

    RPC才是王道。
    learnshare
        22
    learnshare  
       2014-05-09 18:08:03 +08:00
    可以结贴了,某些争议多余且肤浅。程序跑得欢就行,老板只看效果,不管具体实现。
    RIcter
        23
    RIcter  
       2014-05-09 19:05:59 +08:00 via iPad
    @Wuvist 你不是一个人...看到这句我笑喷了...
    cc @jybox
    heganj
        24
    heganj  
       2014-05-10 00:45:10 +08:00
    试试SOAP就知道了
    jybox
        25
    jybox  
    OP
       2014-05-10 02:20:19 +08:00
    @mfaner
    @heganj
    WebDAV 和 SOAP 都是访问资源的协议啊,但是后端 API 实际上更像是 RPC
    chemzqm
        26
    chemzqm  
       2014-05-10 03:06:28 +08:00
    REST只是一套规范,它确实是让一些原本简单的事变得复杂了(其实不过是因为需要思考的多了,开发变慢了),你也完全可以不遵守,但是对于相对复杂的应用而言,它能让接口变得更加简洁,易于理解,同时保证一定程度的扩展性,使用一套规范无论是你自己将来还是新来的维护者都可以更容易的理解你的应用,至于你说的多种状态码完全可以根据你的需求通过中间件统一处理。
    RPC对于单纯的开发来说确实更便捷,但是将来的理解和扩展就没那么容易了。
    sharpnk
        27
    sharpnk  
       2014-05-10 09:23:01 +08:00
    "Status Code 为 200 或 400, 后者会返回一个字符串形式的错误代号。"

    然后你再在前端去解析回复字符串? 实在是无法想象怎么会有人觉得这是个好主意。

    如果每个Web API都能严守http规范来回复请求,这个世界会美好太多。
    mengzhuo
        28
    mengzhuo  
       2014-05-10 11:58:06 +08:00
    正好可以吐槽一下Django rest framework,就是基于Django Model的新框架.
    太他妈的方便了
    reorx
        29
    reorx  
       2014-05-10 12:26:38 +08:00   ❤️ 1
    HTTP 协议本身是很语义化的东西,RESTful 的目的是希望 HTTP 中语义化的成分能和你的接口设计相对应,说白了是让协议和应用相统一的规范。

    但是协议所能表达的语义有限,不可能要求所有的事情都用 GET POST PUT DELETE 等表达,因此我现在的做法是将可以归入 RESTful 范畴的接口用 RESTful 的规范设计,不好归入的在 URL 中加入动词,用 POST 方法做请求。拿 V2EX 的主题顶踩为例,我会设计为 POST /topics/:id/voteup,POST /topics/:id/votedown,并在代码或文档中注明这个接口和其他 RESTful 接口的区别。

    至于 Status Code 的使用,个人认为统一的意义大于规范性,如果你是从头开始主导的项目,当然可以用 Status Code 的不同区分返回的错误,如 @cloudzhou 所列出的那些。但是如果半途加入一个项目,这个项目之前已经是使用 200 返回所有请求,重新设计 Status Code 的成本太高,甚至可能对其他业务造成影响,这时可以考虑在返回数据中描述返回结果的状态。RESTful 也并不是就限制死了你对它的使用,使用方式见仁见智。吸取其中适合自己的成分,作出适合团队协作,提升开发效率,清晰而稳健的接口设计,就是最好的。
    reorx
        30
    reorx  
       2014-05-10 13:04:15 +08:00
    P.S. 上面提到的“在返回数据中描述返回结果的状态”,推荐一个叫 JSend 的简单规范: http://labs.omniti.com/labs/jsend
    j16ZgMV9cs6ZB23n
        31
    j16ZgMV9cs6ZB23n  
       2014-05-10 13:22:28 +08:00
    @mengzhuo 你是说 django-rest-framework.org 这个框架嚒?先前一两周还拜读过这个框架作者的一篇文章(http://www.slideshare.net/silota/building-restful-apis),窝认为一些restful api有趣的概念比如 security(auth),base URL, serialization, timestamps, versioning, caching, gzip, logging 等等(http://www.django-rest-framework.org/api-guide/serializers),对设计整个API的模式大有裨益。

    相关还有这一篇文章 http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api。

    窝非常在意为什么Python就可以有这么好的框架,然后node.js 社区就好像没有(restify?),真的是很羡慕。
    undeadking
        32
    undeadking  
       2014-05-11 23:17:19 +08:00   ❤️ 1
    RPC是企业内部应用开发的产物,如果给移动APP用这种思路设计API,根本就不好用.

    RESTful的URL规范能让运维去直接档掉拖垮服务器的请求,压根不用程序员出马.楼主这种是压根没搞懂RESTful是啥,急于生搬硬套才折腾到自己,一种风格而已,不是要你全部严格遵循的.难道你现在设计数据库还要对着课本的一二三范式去严格遵循吗?
    qibinghua
        33
    qibinghua  
       2014-07-18 22:36:56 +08:00
    喜欢啥就用啥,方便简单就好啊.. 至于安全什么的,在hacker眼里.规范那算个事吗
    picasso250
        34
    picasso250  
       2015-01-07 10:24:10 +08:00
    @cloudzhou
    201 有一个新的资源已经依据请求的需要而建立

    你把201理解成409类似的了

    话说. 我是部分同意楼主的. URL restful, 状态码统一在body里返回(而且要用0表示正常), 才是最省口水的. 大部分程序员只认识http code 中的 200 和 404 ! 我没有在开玩笑.
    cloudzhou
        35
    cloudzhou  
       2015-01-07 15:06:47 +08:00
    @picasso250 是的,我记错了,你这个建议在一些情况下我也同意,在现实中遇到一些问题,比如把 rest http api 放在页面编程的时候遇到的。
    un
        36
    un  
       2015-05-16 23:20:42 +08:00
    @Wuvist 本来就是在请求资源 “皆resource” 不对么?
    Wuvist
        37
    Wuvist  
       2015-06-17 13:04:16 +08:00
    @un 比方说,user login , change password,这是在『请求资源』嘛?
    jybox
        38
    jybox  
    OP
       2015-06-17 16:22:34 +08:00
    @Wuvist 我是楼主,经过一年多的实践,我的观点是有一些变化的,现在我觉得,Restful 是一个简单的、通用的设计,而在设计具体的 API 的时候,可以代入一些 Restful 的风格,这样方便他人理解,也方便配合一些现成的工具,但不必死守 Restful, 具体情况具体分析。
    关于 user login 和 change password, 我觉得其实也可以略牵强地抽象为对资源的操作。user login 可以看作是在创建一个 token, 而 change password 则是在修改用户的密码这样资源。
    Wuvist
        39
    Wuvist  
       2015-06-17 16:30:59 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1026 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:11 · PVG 04:11 · LAX 12:11 · JFK 15:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.