哇,所以这个答案迅速升级...
在过去一年左右的时间我已经尝试通过书籍,邮件列表等出于某种原因,我决定,以获得更好地了解REST的选择你的问题作为我所学到的东西的测试。
对不起:P
让我们把这个整个例子一步简单。不用担心用户上传文件,我们会假设用户只是传递一个字符串。所以,实际上,除了要替换的字符参数(键/值列表)外,他们还要传递一个字符串。稍后我们将处理文件上传部分。
这是一个RESTful的方式,它不需要任何东西存储在服务器上。我将使用一些HTML(尽管破碎,我会忽略像HEAD这样的东西)作为我的媒体类型,只是因为它是相当知名的。
样本解决方案
首先,用户需要访问我们的REST服务。
GET/
<body>
<a rel="http://example.com/rels/arguments" href="/arguments">
Start Building Arguments
</a>
</body>
这基本上为用户提供了一种方式来真正开始对我们的服务进行交互。现在他们只有一个选项:使用链接来构建一组新的参数(最终将用于字符串替换方案中的名称/值对)。所以用户去那个链接。
GET /参数
<body>
<a rel="self" href="/arguments"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}">
<input id="input_string" name="input_string" />
</form>
</body>
这给我们带来的 “论据” 资源的实例。请注意,这不是一个JSON或XML文档,它只返回键/值对的普通数据;它是超媒体。它包含控件,引导用户接下来可以做的事情(有时指的是允许用户“跟随他们的鼻子”)。这个特定的URL(“/ arguments”)表示键/值对的空列表。如果我愿意的话,我可以命名为“/ empty_arguments”:这是一个例子,为什么从URL的角度考虑REST是愚蠢的:它实际上并不重要。
在这个新的HTML,为用户提供了他们可以浏览到三种不同的资源:
- 他们可以使用到“自我”导航到他们目前在相同的资源。
- 他们可以使用第一种形式导航到一个新资源,该资源表示一个参数列表,并使用它们在表单中指定的其他名称/值组对。
- 他们可以使用第二种形式提供他们希望最终替换的字符串。
注意:您可能会注意到,第二种形式有一个奇怪的 “行动” 网址:
/arguments?{key}={value}
在这里,我被骗了:我使用URI Templates。这使我可以指定参数将如何放置到URL上,而不是使用仅使用<input-name>=<input-value>
的默认HTML方案。很显然,为了这个工作,用户不能使用浏览器(因为浏览器没有实现这个功能):他们需要使用理解HTML模板的软件。当然,我使用HTML作为示例,您的REST服务可以使用某种支持URI模板规范定义的URI模板的XML。
无论如何,假设用户想要添加他们的参数。用户使用第一种形式(例如,用“作者”填写“键”输入,用“John Doe”填写“价值”输入)。这导致...
GET /参数?作者约翰=%20Doe
<body>
<a rel="self" href="/arguments?Author=John%20Doe"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
现在这是一个全新的资源。您可以使用单个键/值对将它描述为参数列表(键/值对):“作者”/“John Doe”。 HTML与以前几乎相同,只是有一些变化:
- “自我”链接现在指向当前资源URL(从“/ arguments”更改为“/ arguments?Author = John%20Doe”
- 第一种形式的“动作”属性现在有较长的网址,但我们再次使用URI模板,使我们能够建立一个更大的URI。
- 第二种形式
用户现在希望要添加一个“Date”参数,所以他们再次提交第一个表单,这次用“Date”键和一个值“2003-01-02” 。
GET /参数?作者约翰=%20Doe &日期= 2003-01-02
<body>
<a rel="self" href="/arguments?Author=John%20Doe&Date=2003-01-02"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&Date=2003-01-02&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
最后,用户准备处理他们的字符串,所以他们使用的第二种形式,并填写“ input_string“变量。这又一次使用URI模板,从而将用户带到下一个资源。比方说,该字符串如下:
{Author} wrote some books in {Date}
的结果将是:
GET/processed_string /%7BAuthor%7D +写+有些+书籍+在+%7BDate%7D作者? = John%20Doe & Date = 2003-01-02
<body>
<a rel="self" href="/processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02">
<span class="results">John Doe wrote some books in 2003-01-02</span>
</body>
PHEW!这是很多工作!但它是(AFAIC)RESTful,并且它满足了不需要在服务器端实际存储ANYTHING(包括参数列表或最终想要处理的字符串)的要求。
重要的事情要注意
有一点是这里重要的是,我不只是在谈论的URL。实际上,大部分时间我都在谈论HTML。 HTML是超媒体,这是REST中被遗忘的很大一部分。所有那些声称他们是“宁静的”,他们说“在这个URL上使用这些参数进行GET并在这个URL上使用类似这样的文档进行POST”的API并没有实践REST。罗伊菲尔丁(字面上wrote the book on REST)made this observation himself。
另一件需要注意的事情是,设置参数有点痛苦。在初始GET /到达服务的根目录(你可以认为它是“菜单”)之后,你需要再做5个GET调用才能建立你的参数资源来创建四个关键字的参数资源/值配对。这可以通过不使用HTML来缓解。例如,我已经在我的例子中使用了URI模板,没有理由说HTML对REST来说不够好。使用支持类似于表单的超媒体格式(如XML的一些派生),但能够指定值的“映射”,您可以一次完成此操作。例如,我们可以使用我们的API能够理解的“映射”输入类型是什么,所以长扩展HTML媒体类型,以允许其他所谓的“映射”输入型...
的客户,他们会能够通过一个GET构建他们的参数资源。
在这一点上,你可能甚至不需要“参数”资源。你可以只直接跳到包含映射和实际字符串“processed_string”资源...
什么文件上传?
好吧,所以最初你提到文件上传,以及如何得到这个,而不需要存储文件。那么,基本上,我们可以使用我们现有的示例,但用文件替换最后一步。
在这里,我们基本上做同样的事情和以前一样,除了我们正在上传文件。需要注意的是,现在我们暗示用户(通过表单上的“method”属性)他们应该执行POST而不是GET。请注意,尽管处处听到POST是非安全的(它可能导致服务器发生更改),但是非幂等操作,没有任何说它必须是服务器上的更改状态。
最后,服务器可以返回新文件(甚至更好的办法是返回一些超媒体或LOCATION标头,并带有到新文件的链接,但这需要存储)。
最终评论
这只是一个拿这个具体的例子。虽然我希望你已经获得某种见解,但我会提醒你接受这个福音。我敢肯定,我曾经说过一些事情并不是真正的“休息”。我计划发布这个问题并回答REST-Discuss Mailing List,看看别人对此有何评论。
我希望通过这个来表达一件主要的事情,那就是最简单的解决方案可能就是使用RPC。毕竟,你最初尝试使RESTful试图完成什么?如果你试图告诉人们你完成了“REST”,请记住,大量的API声称自己是“RESTful”,它们真的只是RPC被名词而不是动词所伪装的URL所伪装。
如果是因为您已经听说了REST的一些好处,以及如何通过使您的API RESTful隐含地获得这些好处,那么不幸的事实是,除了URL以外,REST还有更多其他优点,以及您是否对其进行GET或POST 。超媒体扮演着重要角色。
最后,有时您会遇到问题,这意味着您可能会做SEEM非RESTful的事情。也许你需要做一个POST而不是一个GET,因为这个URI(它有一个理论上无限的存储量,但有很多技术限制)会变得太长。那么,你需要做POST。也许
更多资源:
刚刚发现了一个非常尖锐的问题,解决(但不回答)我的问题:http://stackoverflow.com/questions/9010724/rest-and-get-again-这似乎是我的问题的症结所在 - 为什么我们是否应该能够提供复杂/大型数据作为GET请求的一部分? – 2012-03-15 20:13:12