设计休息Web服务的最佳方法,其中包含要从浏览器中使用的二进制数据

时间:2013-01-19 14:33:36

标签: rest backbone.js binary-data restful-architecture

我正在开发一个json rest web服务,该服务将使用使用backbone.js构建的单个网页应用程序进行消费

此API将允许消费者上传与某个实体相关的文件,例如与项目相关的pdf报告

在堆栈溢出中搜索并进行一些研究我带来了这些可能的方法:

第一种方法: base64编码数据字段

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  content: '<base64 encoded binary data>'
}

第二种方法:多部分表格帖子:

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
}

作为回复,我将获得一个报告ID,然后我将发布另一篇文章

POST: /api/projects/234/reports/1/content
enctype=multipart/form-data

然后只发送二进制数据

(看看这个:https://stackoverflow.com/a/3938816/47633

第三种方法:将二进制数据发布到单独的资源并保存href

首先我在客户端生成随机密钥并在那里发布二进制内容

POST: /api/files/E4304205-29B7-48EE-A359-74250E19EFC4
enctype=multipart/form-data

然后

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  href: '/api/files/E4304205-29B7-48EE-A359-74250E19EFC4'
}

(见:https://stackoverflow.com/a/4032079/47633

我只是想知道我是否可以使用任何其他方法,每种方法的优点/缺点,以及是否有任何既定的方法来处理这类要求

我在第一种方法中看到的最大问题是,我必须在客户端上完全加载和base64编码文件

一些有用的资源:

3 个答案:

答案 0 :(得分:13)

我的研究结果:

  1. 单个请求(包含数据)

    请求包含元数据。数据是元数据的属性并进行编码(例如:Base64)。

    优点:

    • 事务
    • 每次都有效(没有遗漏的元数据或数据)

    缺点:

    • 编码使请求非常大

    例子:

  2. 单个请求(多部分)

    请求包含一个或多个包含元数据和数据的部分。

    内容类型:

    优点:

    • 事务
    • 每次都有效(没有遗漏的元数据或数据)

    缺点:

    • 内容类型协商很复杂
    • 数据的内容类型在WADL
    • 中不可见

    例子:

    • Confluence(包含数据和元数据的部分)
    • Jira(一部分用于数据,元数据仅用于文件名和mime类型的部分标题)
    • Bitbucket(其中一部分是数据,没有元数据)
    • Google Drive(其中一部分用于元数据,一部分用于部分数据)
  3. 单个请求(HTTP标头和网址中的元数据)

    请求正文包含数据和HTTP标头,URL包含元数据。

    优点:

    • 事务
    • 每次都有效(没有遗漏的元数据或数据)

    缺点:

    • 无法嵌套元数据
  4. 两个请求

    一个元数据请求和一个或多个数据请求。

    优点:

    • 可伸缩性(例如:数据请求可以转到存储库服务器)
    • 可恢复(参见例如Google Drive

    缺点:

    • 不是交易
    • 并非每次都有效(在第二次请求之前,缺少一部分)

    例子:

答案 1 :(得分:8)

我无法想到任何其他方法。

在你的3种方法中,我最常使用方法3。我看到的最大区别是第一种方法和另外两种方法:将元数据和内容分成2个资源

  • Pro:可伸缩性
    • 当您的解决方案涉及发布到同一服务器时,可以轻松更改此内容以将内容上载到单独的服务器(即Amazon S3)
    • 在第一种方法中,向用户提供元数据的同一服务器将会被大型上传文件阻止。
  • Con:孤立数据/增加的复杂性
    • 上传失败(元数据或内容)会在服务器数据库中留下孤立的数据
    • 可以使用预定作业清除孤立数据,但这会增加代码复杂性
    • 方法II减少了孤儿的可能性,但是当您阻止第一次POST的响应时,会以更长的客户端等待时间为代价

第一种方法似乎最直接的编码。但是,如果预计不经常使用此服务,并且您可以为用户文件上传设置合理的限制,我只会使用第一种方法。

答案 2 :(得分:5)

我认为最终的方法是3号(单独的资源),主要原因是它允许最大化我从HTTP标准获得的值,这与我对REST API的看法相匹配。例如,假设正在使用有良好基础的HTTP客户端,您将获得以下好处:

  • 内容压缩:您可以通过允许服务器使用压缩结果进行优化(如果客户端表明它们支持,您的API未更改,现有客户端继续工作,未来客户端可以使用它)
  • 缓存:If-Modified-Since,ETag等。客户可以建议完全重写二进制数据
  • 内容类型抽象:例如,您需要上传的图片,其类型可以是image/jpegimage/png。 HTTP标头接受内容类型为我们提供了一些优雅的语义,可以在客户端和服务器之间进行协商,而无需将其全部硬编码为模式和/或API的一部分< / LI>

另一方面,我相信如果所讨论的二进制数据不是可选的,这种方法并不是最简单的,这是公平的。在这种情况下,Eric Hu's answer中列出的缺点将发挥作用。