文件(即图像)处理

我们正在开发具有REST API的服务器,它接受并响应JSON。 问题是,如果你需要从客户端上传图片到服务器。

还要注意,我在谈论用例,其中实体(用户)可以拥有文件(carPhoto,licensePhoto),并且还具有其他属性(名称,电子邮件...),但是当您创建新用户时,您不会发送这些图像,它们在注册过程后添加。


我知道的解决方案,但他们每个人都有一些缺陷

1.使用multipart / form-data而不是JSON

好:POST和PUT请求尽可能RESTful,它们可以包含文本输入和文件。

缺点:它不再是JSON,与多部分/表单数据相比,它更容易测试,调试等

2.允许更新单独的文件

POST请求创建新用户不允许添加图像(这在我们的用例中是如何说明的),上传图片是通过PUT请求作为multipart / form-data来完成的,例如/ users / 4 / carPhoto

好:所有内容(除了文件上传本身)都保留在JSON中,它很容易测试和调试(您可以记录完整的JSON请求,而不用担心它们的长度)

缺点:这并不直观,你不能立即POST或PUT实体的所有变量,而且这个地址/users/4/carPhoto可以被认为更像一个集合(REST API的标准用例看起来像这样/users/4/shipments )。 通常你不能(并且不想)GET / PUT实体的每个变量,例如用户/ 4 /名称。 您可以使用GET获取名称,并在用户/ 4处使用PUT更改它。 如果id后面有东西,通常是另一个集合,例如users / 4 / reviews

3.使用Base64

将它作为JSON发送,但使用Base64编码文件。

好:与第一种解决方案相同,它尽可能是RESTful服务。

缺点:测试和调试再次糟糕得多(主体可能有兆字节的数据),客户端和服务器的规模和处理时间都有所增加


我真的很想使用解决方案号。 2,但它有其缺点......任何人都可以给我一个更好的“最好”解决方案的见解?

我的目标是尽可能多地包含尽可能多的RESTful服务,同时我希望尽可能简单。


有几个决定要做

  • 第一个关于资源路径

  • 将图像建模为自己的资源:

  • 嵌套在用户(/ user /:id / image)中:用户和图像之间的关系是隐含的

  • 在根路径(/ image)中:

  • 客户负责建立图像和用户之间的关系,或者;

  • 如果在用于创建映像的POST请求中提供了安全上下文,则服务器可以隐式地在经过身份验证的用户和映像之间建立关系。

  • 将图像嵌入为用户的一部分

  • 第二个决定是关于如何表示图像资源

  • 由于Base 64编码JSON有效负载
  • 作为多部分有效载荷
  • 这将是我的决定轨道:

  • 除非有强有力的例子,否则我通常喜欢设计而不是性能。 它使系统更易于维护,并且可以被集成商更容易地理解。
  • 所以我的第一个想法是去图像资源的Base64表示,因为它可以让你保存所有的JSON。 如果您选择此选项,则可以根据需要为资源路径建模。
  • 如果用户和图像之间的关系是1到1,那么我倾向于将图像建模为属性,特别是如果两个数据集都同时更新。 在任何其他情况下,您可以自由选择将图像建模为属性,通过PUT或PATCH更新它,或作为单独的资源。
  • 如果您选择多部分有效载荷,我觉得不得不将图像建模为自己的资源,以便其他资源(在我们的例子中为用户资源)不会受到为图像使用二进制表示的决定的影响。
  • 然后问题选择base64 vs multipart会有什么性能影响吗? 。 我们可以认为以多部分格式交换数据应该更有效率。 但是这篇文章展示了这两种表述在大小方面的差异很小。

    我的选择Base64:

  • 一致的设计决策
  • 性能影响微乎其微
  • 当浏览器了解数据URI(base64编码图像)时,如果客户端是浏览器,则不需要转换这些数据URI
  • 我不会投票决定是否将其作为属性或独立资源,这取决于您的问题域(我不知道)以及您的个人偏好。

  • OP在这里 (我在两年后回答了这个问题,Daniel Cerecedo的帖子一次也不错,但是网络服务发展非常快)

    经过三年的全职软件开发 (同时关注软件架构,项目管理和微服务架构),我绝对选择第二种方式(但是使用一个通用端点)作为最佳方式。

    如果您对图像有特殊的端点,它会为您处理该图像提供更多的权力。

    对于移动应用程序(iOS / Android)和前端(使用React),我们都有相同的REST API(Node.js)。 这是2017年,因此你不想存储图片本地化,你想上传它们来云存储(谷歌云,S3,cloudinary,...),因此你想要一些一般的处理。

    我们的典型流程是,只要您选择图像,它就开始在后台上传(通常在/图像端点上POST),上传后返回您的ID。 这是真正用户友好的,因为用户选择图像,然后通常继续与其他字段(即地址,名称,...),因此,当他点击“发送”按钮时,图像通常已经上传。 他不会等待并观看屏幕显示“正在上传...”。

    获取图像也是一样。 尤其要感谢手机和有限的移动数据,你不想发送原始图像,你想发送调整大小的图像,所以他们不会占用太多的数据(并且使您的移动应用程序更快,您通常不想调整它的大小,你想要的图像完全符合你的观点)。 出于这个原因,好的应用程序正在使用像cloudinary(或我们有我们自己的图像服务器调整大小)。

    此外,如果数据不是私密的,那么您只需将URL发送回app / frontend,然后直接从云存储中下载它,这为您的服务器节省了大量带宽和处理时间。 在我们更大的应用程序中,每个月都会下载大量的TB数据,您不希望直接在每个REST API服务器上处理它,而这些服务器都集中在CRUD操作上。 你想在一个地方处理它(我们的Imageserver,它有缓存等),或者让云服务处理所有这些。


    缺点:你应该考虑的唯一“缺点”是“未分配图像”。 用户选择图像并继续填写其他字段,但他然后说“nah”并关闭应用程序或选项卡,但同时您成功上传图像。 这意味着您已经上传了未分配到任何地方的图像。

    有几种处理方法。 最简单的一个是“我不在乎”,这是相关的,如果这种情况不经常发生,或者您甚至希望存储用户向您发送的每个图像(出于任何原因),并且您不想要任何删除。

    另一个也很容易 - 你有CRON,即每周都会删除所有未分配的图像,而这些图像比一周还旧。


    你的第二个解决方案可能是最正确的。 您应该按照预期的方式使用HTTP规范和mimetypes,并通过multipart/form-data上传文件。 至于处理关系,我会使用这个过程(记住我对你的假设或系统设计知之甚少):

  • POST/users创建用户实体。
  • POST将图像/images ,并确保返回Location头,其中图像可以每HTTP规范进行检索。
  • PATCH/users/carPhoto并为其分配在给定照片的ID Location的步骤2的报头。
  • 链接地址: http://www.djcxy.com/p/8565.html

    上一篇: file (ie images) processing

    下一篇: Not Acceptable Response" in HTTP?