关于REST,我没有理解的是什么?

18

我正在构建一个框架,并希望使用该框架的开发人员能够允许其部分内容既与其他站点共享数据,又允许其他站点添加/编辑/删除数据。

例如,如果有人创建了一个包含书评、作者、引用、代码示例、评论等内容的网站,开发人员可以使“书评”对其他站点只读,而“评论”对某些站点/用户可读写。这个想法是使用框架来构建应用程序,可以轻松地与其他应用程序相互连接。

我设想通过POST和GET来实现与站点的所有交互,具体如下:

  • /books.php?category=ruby (返回有关Ruby图书的XML集合)
  • /books.php?id=23 (返回特定书籍的XML)
  • /books.php?action=add&title=AdvancedRuby&description=....&securityId=923847203487
  • /books.php?action=delete&id=342&securityId=923847203487

其他应用程序也可以通过以下方式“发现和消费”某个站点的内容:

  • /discover.php (返回所有公共类和可用动作的XML)

实际上,这就是我需要的,以使该框架成为开发人员快速创建松散连接站点的一种方式。

我想知道的是,在开始实现之前,REST的重要/有趣部分是否还存在我不了解但应该构建到框架中的部分,例如:

  • REST需要GET、POST、PUT和DELETE。为什么我需要“PUT”和“DELETE”?如果不使用它们,我是否会失去利用某些标准的机会?
  • 我的“discover.php”文件类似于Web服务中的WSDL文件。在REST的描述中,我很惊讶似乎没有一种标准的方法来发现RESTful服务提供的服务,或者有吗?
  • 如果客户端网站试图向服务端网站添加书籍,但未收到任何“成功”响应,则会反复尝试,直到得到响应。服务端网站将不会重复添加相同的书籍。这是我对REST中数据完整性的理解,除此之外还有别的吗?
  • 最终,我希望拥有多个具有相同丰富类的网站,例如“BookReview”,以便客户端网站能够执行以下代码:

    $bookReview = new BookReview("http://www.example.com/books.php?id=23"); $book->informAuthor("在我们的网站上发表了有关您书评的评论...");

  • 然后,服务器站点会向该评论的作者发送电子邮件。 这种类型的交互是否是RESTful哲学的组成部分,还是REST仅仅是通过XML、JSON进行数据交换?


    1
    顺便提一下,永远不要将GET用于DELETE操作,使用POST。 - Esteban Küber
    我认为你没有理解的关键是宏大的“超媒体作为应用状态引擎”或HATEOAS概念。你谈了很多关于URL结构的事情,但实际上需要讨论媒体类型以及它们如何“链接”彼此。请参考Vinko Vrsalovic的答案,这将指引你朝着正确的方向前进,同时也请阅读更多关于HATEOAS的内容,直到它开始变得真正有意义。我花了一段时间才明白它的含义 ;) - Day
    7个回答

    23

    如果我不使用这些,我会失去利用某些标准的机会吗?

    您将无法使用HTTP标准。当然,您可以使用GET参数来完成相同的操作。但这不是REST,而是类似RPC。

    我可以建议一本书——RESTful Web Services,作者是Leonard Richardson和Sam Ruby。它非常有趣,展示了不同方法之间的差异。

    稍微详细地回答您的问题:选择哪种方式取决于您。理论上,RESTful和RPC-like两种方法都可以完成相同的工作。使用RESTful时,您使用底层HTTP协议作为协议。使用RPC时,您仅将HTTP用作传输手段,并在传输的数据中隐藏工作指令。这会导致(不必要的)开销。

    只需看看您的两个示例:

    • /books.php?action=add&title=AdvancedRuby&description=....&securityId=923847203487
    • /books.php?action=delete&id=342&securityId=923847203487
      • 有POST和PUT或DELETE,为什么还需要action=add和action=delete?
      • 有HTTP身份验证。为什么要发明一个可能不太安全的securityId?
      • 顺便说一下:不应通过GET允许对数据进行更改。这只是不应该做的事情(另一个话题,不过 ;))

    8
    我建议你阅读Roy Fielding的这篇文章
    其中一个重点是:
    • REST API 应该在定义用于表示资源和驱动应用程序状态的媒体类型或在定义扩展关系名称和/或启用超文本标记的现有标准媒体类型时,几乎所有的描述性工作都要花费精力。在感兴趣的 URI 上使用哪些方法所花费的任何努力都应完全在媒体类型的处理规则范围内定义(在大多数情况下,已由现有媒体类型定义)。[在这里失败意味着带外信息驱动交互而不是超文本。]

    • REST API 不能定义固定的资源名称或层次结构(客户端和服务器之间的明显耦合)。服务器必须有自己控制命名空间的自由。相反,允许服务器通过在媒体类型和链接关系中定义这些指令来指导客户端如何构造适当的 URI,例如在 HTML 表单和 URI 模板中所做的那样。[在这里失败意味着客户端由于带外信息(如特定于域的标准)而假定资源结构,这是面向数据的等效于 RPC 的功能耦合]。

    当然,你可以像你描述的那样采用类似 RPC 的方法并取得成功,而且比“正确的 REST API”更容易理解。 REST 最被误解的方面是,一旦定义,它应该自动工作,你不应该定义“使用此方法前往此 URI 以获取该答案”,所有这些都应该由你提供的媒体类型和让客户端知道如何找到相关资源的手段隐含表示。

    4
    +1 回答很棒。但对我来说,Roy的帖子总是太抽象和学术化,难以理解并用于向人们解释如何实现REST API。我发现使用“超媒体作为应用程序状态引擎”的最佳解释是http://www.infoq.com/articles/subbu-allamaraju-rest。Subbu提供了一个具体的例子,将RPC样式接口(就像OP所建议的那样)转换为正确的REST API,最终帮助我理解了它们之间的区别。 - Day
    我想问一下,作为一个拼命努力理解RAILS中似乎难以理解的概念的人,我应该如何理解这个答案的意思?我必须接受过计算机科学培训,还是需要在维基百科上查每一个术语才能理解其含义?我不明白为什么人们不使用更简单(且不带有太多含义的)的语言。 - moosefetcher
    @moosefetcher,术语的存在是有原因的。扩展这个答案中使用的每个“负荷”术语同样会将答案从4段扩展到20段。 - Vinko Vrsalovic

    4

    来自RestWiki

    • 对标识符进行GET意味着“以特定文档格式提供我的信息副本”。
    • 对该标识符进行PUT意味着“用我的信息替换你的信息”。
    • POST添加信息,
    • DELETE删除信息。

    考虑到这一点,将其应用于您的应用程序应该非常简单易懂。


    3
    使用Restlet框架,我们试图在HTTP细节之上提供这种抽象级别,并使REST概念更加具体化(许多都有匹配的类,如Component、Connector和Representation):http://www.restlet.org/ 我们是务实的编码人员,我们的用户使用我们的RESTful框架(适用于Java和GWT)开发现实世界的应用程序。REST支持者并非都是一本正经的,但像每个重要技术一样,有一个学习曲线。

    2
    我会尝试将其翻译成符合RESTful标准的格式。

    /books/ruby

    GET /search?type=books&category=ruby
    

    /books.php?id=23

    GET /books/23 (or /books/23.xml)
    

    /books.php?action=add&title=AdvancedRuby&description=....&securityId=923847203487

    POST /books
    title=AdvancedRuby&description=A+great+book...
    

    /books.php?action=delete&id=342&securityId=923847203487

    DELETE /books/342
    

    许多开发者都使用GET和POST方法,其中后者可能是:
    POST /books/342
    status=Deleted
    

    1

    REST 是一项有趣且具有潜在用途的技术,但不幸的是,它似乎吸引了最苛刻的开发者集合。

    他们似乎更愿意实现严格遵循 REST 教条的应用,即使这意味着完全失去功能。任何与纯 REST 有所偏差的行为都将被视为异端邪说。


    2
    我不会说这是异端邪说,但如果你拆掉直升机的旋翼并加上机翼,然后称之为飞机,这显然是错误的。而这正是REST热潮中经常发生的事情——人们编造一些URI,然后称其为RESTful,其实最多只是没有旋翼并粘上机翼的RPC。 - Vinko Vrsalovic
    此外,声称只有通过完全丧失功能才能使用定义的REST是可行的,这意味着以下情况之一:1)您不理解它;2)已经成功使用它的人都不理解它,而这只是纯粹的运气;3)第二种情况中的人都在撒谎。 - Vinko Vrsalovic
    好的,我应该在我的牢骚结尾加上一个微笑符号。REST 的好处是一切都已经存在,不好的地方是 REST 是已经存在的一切的子集(出于非常好的原因!),所以 REST 的合规性成为了自律的练习。 - James Anderson
    尽管这并没有回答问题:宗教部分是真的 ;) - BlaM
    这并不是一个真正的答案,更像是一条评论。我认为一些迂腐是有道理的,因为REST引起了很多误解。</pedant> - Day

    -4

    我对REST并不感到轻松。对我来说,它是一个伟大的概念,从抽象的角度来看,适用于那些不必处理复杂HTTP通信中涉及的更加繁琐编码问题的Web极客。

    如果有一个REST API可以将我们从所有HTTP中抽象出来,那该多好啊。但事实并非如此。相反,REST支持者必须向您推销这样的API,并面临调试和测试等相关问题。

    当我看到REST 1.0标头时,我会再次审视它,以找到值得努力的优势。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接