【问题标题】:REST API and delivering a binary resourceREST API 和交付二进制资源
【发布时间】:2012-08-24 12:13:27
【问题描述】:

使用 REST API 交付二进制资源(如 pdf 文件)的惯例是什么?您是否只是在 JSON 或 XML 响应中返回资源的 URL,例如 {"url" : "http://example.com/document.pdf"} ?

我试图理解 URI 和 URL 之间的区别,并保持 RESTful 哲学。诚然,这对我来说是新的,所以我可能会误解一些事情。

【问题讨论】:

    标签: rest


    【解决方案1】:

    本节假设您的意思是:我如何告诉用户在哪里可以找到二进制资源

    URI 和 URL 之间的区别与二进制与非二进制数据类型没有任何关系 (see also)。

    如果您返回的主要是 JSON,那么 url 条目是一种常见的方法。如果您正在做一些更类似于 HTML/XML 的事情,那么像 <link> 元素这样具有良好的 rel 属性的东西很有意义。

    显然,如果客户端向您提供给他们的直接 URL 发出 GET 请求,那么您应该将文件发送给他们,除非他们发送了一堆内容协商标头,从而有效地阻止您完成他们的请求。在这种情况下,406 Not Acceptable 响应(或 the official definition)很有意义。

    如果您的问题是其他意思,请澄清。

    漫无边际的“这样做”部分

    首先:忽略 URL 与 URI。它与此无关。完全没有。

    下一步:如果您的问题不是“我如何链接到资源”(这可能会受到我将要讨论的内容的影响),而是“如果我的资源只是一个 PDF 文件怎么办”,那么您有解决它的各种选项。首先,你需要退后一步,更抽象地思考(一点点)。您的资源几乎肯定不是“PDF 文件”。它是“用户上传的文件”,或“我生成的 PDF 版本的报告”等。

    在第一种情况下,除了他们发送给您的二进制文件之外,您可能没有任何资源表示,这完全没问题。当您收到指向该资源 URL 的 GET 时,您可能不需要执行任何类型的内容协商。只需将文件发送给他们,但要遵守我上面提到的关于 406 的警告。

    在第二种情况下,您可能拥有该资源的各种表示形式:CSV、HTML、LaTeX,应有尽有。在这种情况下,当您收到指向资源 URL 的 GET 时,您确实需要进行一些内容协商,以便知道是否向他们发送 PDF 文档或其他内容。您可能拥有资源的 JSON 表示形式,它只是您用于生成 PDF 的原始数据。

    在任何一种情况下,如果您有一个完全是关于资源的元数据的表示,那将是出乎意料的。如果需要(通常是,有时不是),显式的外部元数据(与嵌入在二进制资源中的元数据相反,例如 PDF 中的作者和标题信息)最常被建模为单独的资源。

    最后,正如@monitorjbl 所说:您可能希望将二进制数据直接嵌入文本格式,例如 JSON 或 XML。有很多方法可以做到这一点,通常涉及“base64-encoded”这个词,但这通常不是最好的方法。一般来说,您不应该混合使用二进制数据和文本数据。

    【讨论】:

    • 这就是我的意思,主要是。当 GET 请求到来时,我可以吐出 pdf,但这似乎不是 RESTful。我假设您应该只返回资源的“表示”而不是资源本身(同样,我可能在这里误解了一些东西)。这就是为什么我对 URI 和 URL 有点困惑。您的链接很有帮助,但我仍在努力澄清它。
    • @Drinian 我更新了我的答案;希望它现在更有用。
    • 谢谢。 pdf 有一个数据表示,即发票,但 pdf 具有唯一数据(签名)。我认为这意味着最好的解决方案就是发回指向 pdf 的 URL?如果是这样,那么该 URL 不被视为 API 的一部分,对吗?
    • 或者我应该让 GET 请求根据用户想要纯数据还是实际 pdf 发送不同的 Accept 标头?
    • @Drinian 只是为了确保我清楚:您有一张可以以“原始数据”形式或 PDF 形式查看的发票?我倾向于内容协商,但由于 PDF 有签名(实体发票的扫描件?),它在我的脑海中并不是一成不变的。与将要使用您的服务的人交谈以了解他们的喜好可能会有所帮助。
    【解决方案2】:

    无论是否二进制,您的 REST 资源都应使用超媒体类型进行描述。

    • 如果您的 REST 客户端以 msgpack 格式 PUT/POST 资源,REST 服务器仍然可以读取此消息并更新/创建资源。那为什么不呢。
    • 如果您的 REST 客户端以 PDF 格式 PUT/POST 资源,我猜您将无法提取正确创建/更新资源所需的所有信息。所以,没有。

    在最后一种情况下,您可能正在处理类似“Google 驱动器”的服务:这些 PDF 本身不是您的资源,应该由您的实际资源链接(即 URL 应该在您的资源中)。

    即使 Google Drive 可能不是完美的 REST API (API reference),它也同时处理 JSON 资源和实际的二进制文件。

    【讨论】:

      【解决方案3】:

      根据我的经验,这样做与 REST Web 服务的想法背道而驰。与传统的 RESTful 服务不同,您永远无法缓存此响应而不引起严重的头痛。此外,由于您必须将服务作为文本使用才能读取 XML/JSON,因此您可能无法同时针对文本和二进制读取进行优化。更不用说,您必须始终 需要二进制信息,否则当您只需要文本数据时,性能会受到相当大的影响。如果您总是需要二进制数据,不妨问问自己为什么需要网络服务?

      这并不是说这是不可能的(毕竟有 BSON)或者不存在这种情况的用例,但是您应该非常确保您无法逃避对二进制数据的单独请求在您尝试执行此操作之前。将二进制数据嵌入到专为文本设计的文档格式中效率非常低,并且这种格式的数据会比原始字节大得多。

      顺便说一句,如果您总是使用矢量图形资源(如 SVG 或某些类型的 PDF)执行此操作,则可以将其表示为 XML 数据。同样,您可能不想这样做,因为它会增加您的有效负载,但它是解决“需要二进制文件”问题的一种选择。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-09
        • 2023-01-18
        • 1970-01-01
        • 2015-07-02
        相关资源
        最近更新 更多