有效的 URI

有效的 URI(有时也称为更具体的术语 URL [1])是设计可用 HTTP API 的核心。统一资源标识符由 RFC 3986 定义,其在 HTTP 中的使用在 RFC 7230 中得到澄清。URI 是 API 中资源的标识符,也用于在网络上定位和寻址该资源。

URI 分为几个部分:schemeauthoritypathqueryfragment(请参阅 RFC 3986 以获取更多详细信息)。作为 API 服务开发人员,pathquery 最为相关;fragment 通常不会发送到服务,并且对 schemeauthority 的控制机会和理由也很少。

以下内容将仅关注 pathquery

值得了解的事项

  • pathquery 的值区分大小写。也就是说,如果您有两个看起来相似的 URI,http://example.com/foo/BAR?dEtail=1http://example.com/foo/bar?detail=1,它们并不等效。服务器应用程序可以选择规范化 URI,但这并不推荐,因为它不符合常用用法,也不符合 RFC 7230
  • 虽然 path 通常看起来像一个层次结构路径(/collection/item/sub-resource/detail),类似于磁盘上文件的完整文件名,但这只是为了方便起见,并且是使 URI 易于人类理解的产物。事实是,整个 URI 标识资源,而不仅仅是路径的最后一个片段。
  • URI 设计的全部意义 [2] 是使 URI 易于人类理解,既方便 API 的用户,也方便 API 的未来维护者。

URI 设计通用建议

注意

这远非详尽的列表。这仅仅是一个起点,我们可以从中积累有关如何构建良好 URI 的合理建议。

  • 由于单个 URI 标识单个资源,因此在构建服务时,还需要保持以下两点:

    • 任何资源应该只有一个 URI。在可能的情况下,不要提供多种引用相同资源的方式。使用 HTTP 重定向来解析间接请求到正确的规范 URI,并使用内容协商来请求不同的表示形式。

    • 任何给定的资源,由于应该只有一个 URI,应该仅对该 URI 响应所有相关的 HTTP 方法,而不要为某些方法提供辅助 URI。例如

      使用

      GET /resources/1322b203bdc64c13b6e72b04d43e8690
      DELETE /resources/1322b203bdc64c13b6e72b04d43e8690
      

      绝不要

      GET /resources/1322b203bdc64c13b6e72b04d43e8690
      DELETE /resources/1322b203bdc64c13b6e72b04d43e8690/delete
      
  • 通常,API 会有代表资源的集合的 URI,以及该集合中单个成员的层次结构。例如 [3]

    GET /birds
    
    {"birds": [
        {
            "name": "alpha",
            "type": "crow"
        },
        {
            "name": "beta",
            "type": "jackdaw"
        }]
    }
    
    GET /birds/alpha
    
    {
        "name": "alpha",
        "type": "crow"
    }
    

    这样做是合理的,因为它有助于使 API 的元素易于理解。

  • 如果使用上述层次结构,重要的是所有采用第二种形式的 URI(/birds/alpha)具有相同的语义,并且始终标识属于该集合的资源(在本例中“是一只鸟”)。

    OpenStack 中有多个例子违反了这一概念。例如,在 nova 的 os-cells API 中,可以GET /os-cells获取单元列表,GET /os-cells/some-name获取名为some-nameGET /os-cells/details获取与GET /os-cells相同的信息,但包含更多详细信息。

    对于这个特定的例子,一种方法(有几种选择)是在保持 URI 语义的同时,使用 query 来增强现有的集合 URI,以指示对更多详细信息的渴望 [3]

    GET /os-cells?details=true
    

    待办事项

    关于如何指示布尔查询参数,目前尚存在未解决的争论。任何details=true, details=1或者details都有意义。上述内容不应被视为对任何 query 格式的支持。相反,它只是为了演示 URI 的 path 部分中更清晰的语义。

复杂查询

在某些情况下,可能需要返回与一组过滤条件匹配的资源集合。对于这些情况,使用 GET 方法,并创建一个将所有要求连接起来的查询字符串。例如,如果您需要返回所有蓝色且具有迁徙性且会游泳的鸟类,则 URI 将如下所示:

GET /birds?color=blue&migratory=true&swimming=true

URI 的长度限制因服务器和客户端而异。最严格的是一些浏览器,它们具有大约 2K 的最大 URI 长度,而像 Apache 这样的 Web 服务器将 URI 限制在约 8K 左右。如果表达请求的复杂需求所需的 URI 长度可能超过这些限制,可以使用POST方法,并将过滤条件传递到请求主体中。

脚注

[1]https://en.wikipedia.org/wiki/Uniform_Resource_Locator
[2]另一种观点认为,URI 应该是完全不透明的标识符,计算机使用它们来交换信息。这种观点很有价值,因为它允许标识符充当可互换的引用,但它低估了创建服务的各种客户端的价值和成本。如果我们希望鼓励这种多样化的集合,那么拥有易于人类理解的 URI 将有所帮助。
[3](1, 2) 这些只是示例请求和响应,不应被视为明确描述正确的格式。

目录

上一主题

日期和时间约定

此页面