【问题标题】:What's the RESTful way to check whether the client can access a resource?检查客户端是否可以访问资源的 RESTful 方法是什么?
【发布时间】:2023-04-06 04:27:01
【问题描述】:

我正在尝试确定 REST API 中的最佳实践,以确定客户端是否可以访问特定资源。两个简单的示例场景:

电话目录查找服务。客户通过访问 eg.
GET http://host/directoryEntries/numbers/12345
查找电话号码 ...其中12345 是要尝试在目录中查找的电话号码。如果存在,它将返回电话号码所在的人的姓名和地址等信息。

视频格式转换服务。客户将一种格式的视频提交给 eg.
POST http://host/videos/
...并接收服务器为此视频生成的“视频 GUID”。客户端然后检查例如。
GET http://host/videos/[GUID]/flv
... 获取视频,转换为 FLV 格式,如果转换后的版本存在。

您会注意到,在上述两种情况下,我没有提到如果正在检查的资源 不存在 会发生什么。这是我的问题。我在variousotherplaces中读到,客户端检查资源是否存在于此处的正确RESTful方法是调用资源上的HEAD(或者可能是GET),如果资源不存在,它应该期待 404 响应。这很好,除了 404 响应被广泛认为是“错误”; HTTP/1.1 spec 声明 4xx 类状态代码适用于客户端“似乎出错”的情况。可是等等;在这些例子中,客户肯定没有犯错。 预计它可能会返回一个 404(或其他;如果它没有被授权访问此资源,则可能是一个 403),并且它在请求资源时没有犯任何错误。 404 并非旨在指示“错误条件”,它只是信息 - “这不存在”。

正如 HTTP 规范所暗示的那样,浏览器的行为就像 404 响应是一个真正的错误一样。每次 XHR 请求收到 404 时,无论是否由错误处理程序处理,Google Chrome 和 Firebug 的控制台都会在 Javascript 控制台中喷出一条大红色的“404 Not Found”错误消息,并且没有禁用它的方法。这对用户来说不是问题,因为他们看不到控制台,但作为开发人员,当我完全了解时,我不想在我的 JS 控制台中看到一堆 404(或 403 等)错误好吧,它们不是错误,而是由我的 Javascript 代码处理的信息。是线路噪音。在我给出的第二个示例中,线路噪音达到了极端,因为客户端可能会轮询服务器以获取 /flv,因为编译可能需要一段时间,并且客户端希望显示“尚未编译”直到它得到一个非 404。 JS控制台可能每隔一两秒就会出现404错误。

那么,这是我们使用 REST 检查资源是否存在的最佳或最合适的方法吗?我们如何绕过 JS 控制台中的线路噪音?很可能建议,在我的第二个示例中,可以查询不同的 URI 来检查编译的状态,例如:
GET http://host/videos/[GUID]/compileStatus
...但是,对我来说,这似乎有点违反 REST 原则;您没有完全使用 HTTP 并注意 HTTP 标头,而是创建自己的协议,通过该协议您在正文中返回信息,告诉您您想知道的内容,并始终返回 HTTP 200 以关闭浏览器.这是对 SOAP 的主要批评——它试图“绕过”HTTP,而不是充分利用它。根据这一原则,为什么需要返回 404 状态码?您总是可以返回 200 - 当然,200 表示资源的状态信息 可用,状态信息告诉您您真正想知道的信息 - 资源未找到。当然,RESTful 方式应该是返回 404 状态码。

如果我们将它应用到我上面的第一个例子中,这个机制似乎更加人为;客户可能会查询:
GET http://host/directoryEntries/numberStatuses/12345
......当然会收到200;号码12345状态信息 存在,并告诉您...在目录中找不到该号码。这意味着查询的任何数字都是“200 OK”,即使它可能不存在 - 这看起来像是一个好的 REST 接口吗?

我错过了什么吗?是否有更好的方法来确定资源是否存在 RESTfully,或者是否应该更新 HTTP 以指示非 2xx 状态代码不一定被视为“错误”,而只是信息?浏览器是否应该能够进行配置,以便它们不会总是在 JS 控制台中将非 2xx 状态响应输出为“错误”?

PS。如果你读到这里,谢谢。 ;-)

【问题讨论】:

    标签: javascript http rest google-chrome firebug


    【解决方案1】:

    完美可以使用 404 来表示找不到资源。 “RESTful Web Services”一书中的一些引述(顺便说一句,关于 REST 的非常好的书):

    404 表示服务器无法将客户端的 URI 映射到 资源。 [...] Web 服务可以使用 404 响应作为信号 URI 是“免费”的客户端;然后客户端可以创建一个新的 通过向该 URI 发送 PUT 请求来获取资源。请记住,404 可能 是掩盖 403 或 401 的谎言。可能是资源 存在,但服务器不想让客户端知道。

    当服务找不到请求的资源时使用404,不要过度使用来指示实际上与资源存在无关的错误。此外,客户端可以“查询”服务以了解此 URI 是否免费。

    执行长时间运行的操作,例如视频文件的编码

    HTTP 有一个同步的请求-响应模型。客户端打开一个 到服务器的 Internet 套接字,发出请求,并保留套接字 打开,直到服务器发送响应。 [...]

    问题不是所有的操作都可以在我们的时间内完成 期望接受一个 HTTP 请求。有些操作需要数小时或数天。一个 在这种不活动之后,HTTP 请求肯定会超时。 即使没有,谁愿意让套接字打开几天 等待服务器响应?有没有办法暴露这种 通过 HTTP 异步操作?

    有,但需要将操作拆分为两个或多个 同步请求。第一个请求产生操作,并且 随后的请求让客户端了解 手术。秘密是状态码 202(“已接受”)。

    所以你可以用POST /videos 来创建一个视频编码任务。该服务将接受任务,以 202 回答并提供指向描述任务状态的资源的链接。

    202 Accepted
    Location: http://tasks.example.com/video/task45543
    

    客户端可以查询这个 URI 来查看任务的状态。任务完成后,资源的表示将变为可用。

    【讨论】:

    • “使用 404 表示未找到资源是完全可以的” - 好的,但是你的建议是什么,它会导致浏览器污染 JS 控制台,负载为404错误?而且,HTTP/1.1 规范说 4xx 代码表明客户端在某种程度上犯了错误是错误的吗?
    • 这不是客户端 JS 代码的错误,而是特定于浏览器的问题。 You can disable 404 errors。或者,您可以使用带有任务队列的方法,它可以避免 404
    【解决方案2】:

    我认为您已经更改了请求的语义。 使用 RESTful 架构,您正在请求资源。因此,请求不存在或未找到的资源被视为错误。

    我用:

    • 如果GET http://host/directoryEntries/numbers/12345 不存在,则为404。

    • 400 实际上是一个错误的请求400 Bad Request

    也许,在您的情况下,您可以考虑改为搜索。 使用资源集合上的查询参数完成搜索

    你想要的是 GET http://host/directoryEntries/numbers?id=1234 如果不存在或匹配列表,它将返回 200 和一个空列表。

    【讨论】:

    • 搜索选项是一个很好的解决方案,可以阻止浏览器在控制台中给出 404 错误,我同意......但这似乎只是请求 /numbers/12345 的另一种(可能不太 RESTful)方式.
    • 它们的意思相似,但不同。第一种情况是使用URI(即不存在的实际号码资源)。第二个是查询一个确实存在的 URI(数字)并返回可能为空的匹配项
    【解决方案3】:

    IMO 客户端确实错误地请求了不存在的资源。在您的两个示例中,服务可以以不同的方式设计,因此可以在客户端避免错误。例如,在已分配 GUID 的视频转换服务中,videos/id 处的消息正文可以包含指示转换是否完成的标志。

    同样,在电话目录示例中,您正在搜索资源,这可以通过 /numbers/?search_number=12345 等方式处理,以便服务器返回匹配资源列表,然后您可以进一步查询.

    浏览器是为使用 HTTP 规范而设计的,显示错误是真正的响应(也很有帮助)。但是,您需要将 Javascript 代码视为独立于浏览器的实体。所以你有你的 Javascript REST 客户端,它知道服务是什么样的,而浏览器对你的服务有点愚蠢。

    此外,REST 在理论上独立于协议。 HTTP 恰好是使用 REST 的最常见协议。我能想到的另一个例子是 Android 内容提供程序,它的设计是 RESTful 但不依赖于 HTTP。

    【讨论】:

    • 正如我对 jermel 所说,?search_number=12345 是一个很好的解决方案,可以阻止浏览器将错误放入控制台,但由于 12345 是一个唯一 ID,它看起来就像另一个(也许较少 RESTful) 的说法 /12345.
    • 其实没有。您正在向 /numbers/ 的资源列表发送修饰符参数。这与搜索 /locations/?lat=12.0&lng=76.0&radius=100.0 等地理位置的方式相同。
    【解决方案4】:

    我只见过 GET/HEAD 请求在资源不存在时返回 404(未找到)。我认为,如果您只想获取资源的状态,则头部请求会很好,因为它不应该返回资源的主体。通过这种方式,您可以区分尝试检索资源的请求和尝试检查资源是否存在的请求。

    http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

    编辑:我记得通过在原始请求中添加一个标头来指示服务器应如何处理 404 错误,从而了解了另一种解决方案。类似于用 200 响应的东西,但是一个空的身体。

    【讨论】:

    • 但我遇到的真正麻烦(包括 GET 和 HEAD)是 404 被认为是错误,而浏览器会以这种方式运行,用无用的 404 错误消息将我的 JS 控制台弄得一团糟。我只想要 JS 控制台中的合法错误。
    • 当然,我想区别在于您希望客户端如何响应不存在的资源与服务器上逻辑上正确的 REST。我记得在一本书中读过一些关于这个的东西,但是我有太多的 REST 书! :) 如果我能找到它,我会编辑我的问题。在我的脑海中,我认为这可能与在请求中添加一个关于客户端希望服务器如何处理 404 错误的标头有关。类似于以 200 响应的内容,但包括一个空正文以指示未找到资源。
    猜你喜欢
    • 2011-10-20
    • 2015-11-15
    • 2011-02-18
    • 2016-03-03
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    相关资源
    最近更新 更多