检查客户端是否可以访问资源的 RESTful 方法是什么?

What's the RESTful way to check whether the client can access a resource?

本文关键字:RESTful 方法 是什么 资源 访问 客户端 是否 检查      更新时间:2023-09-26

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

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

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

您会注意到,在上面的两种情况下,我都没有提到如果正在检查的资源不存在会发生什么。 这是我的问题。 我在其他地方读到,客户端检查资源是否存在的正确 RESTful 方法是调用资源上的HEAD(或可能是GET),如果资源不存在,它应该期待 404 响应。 这很好,除了 404 响应被广泛认为是"错误";HTTP/1.1 规范指出,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 接口吗?

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

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

使用 404 表示找不到资源是完全可以的。《RESTful Web Services》一书中的一些引文(顺便说一下,关于REST的好书):

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

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

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

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

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

有,但它要求将操作拆分为两个或更多 同步请求。第一个请求生成操作,并且 后续请求允许客户端了解 操作。机密是状态代码 202("已接受")。

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

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

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

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

我使用:

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

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

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

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

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

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

浏览器是为使用 HTTP 规范而设计的,显示错误是真正的响应(也非常有用)。但是,您需要将Javascript代码视为与浏览器分开的实体。所以你有你的Javascript REST客户端,它知道服务是什么样的,而浏览器在你的服务方面有点愚蠢。

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

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

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

编辑:我记得通过向原始请求添加一个标头来阅读有关替代解决方案的信息,该标头指示服务器应如何处理404错误。类似于回应 200 的东西,但身体空空如也。