文件(即图像)处理
我们正在开发具有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请求中提供了安全上下文,则服务器可以隐式地在经过身份验证的用户和映像之间建立关系。
将图像嵌入为用户的一部分
第二个决定是关于如何表示图像资源 :
这将是我的决定轨道:
然后问题是 : 选择base64 vs multipart会有什么性能影响吗? 。 我们可以认为以多部分格式交换数据应该更有效率。 但是这篇文章展示了这两种表述在大小方面的差异很小。
我的选择Base64:
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的报头。