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

ope*_*sas 31 rest binary-data backbone.js 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>'
}
Run Code Online (Sandbox Code Playgroud)

第二种方法:多部分形式的帖子:

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
}
Run Code Online (Sandbox Code Playgroud)

作为回复我会得到一个报告ID,然后我会发一个帖子

POST: /api/projects/234/reports/1/content
enctype=multipart/form-data
Run Code Online (Sandbox Code Playgroud)

然后只发送二进制数据

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

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

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

POST: /api/files/E4304205-29B7-48EE-A359-74250E19EFC4
enctype=multipart/form-data
Run Code Online (Sandbox Code Playgroud)

然后

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

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

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

我对第一种方法的看法是,我必须在客户端上完全加载和base64编码文件

一些有用的资源:

dur*_*dur 14

我的研究结果:

  1. 单一请求(包括数据)

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

    优点:

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

    缺点:

    • 编码使请求非常大

    例子:

  2. 单一请求(多部分)

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

    内容类型:

    优点:

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

    缺点:

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

    例子:

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

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

    优点:

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

    缺点:

    • 没有嵌套的元数据
  4. 两个请求

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

    优点:

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

    缺点:

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

    例子:


Eri*_* Hu 8

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

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

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

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


Amr*_*afa 5

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

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

另一方面,我认为如果所讨论的二进制数据不是可选的,那么这种方法并不是最简单的,这是公平的.在这种情况下,Eric Hu的答案中列出的Cons 将发挥作用.