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

时间:2012-04-21 13:59:49

标签: javascript http rest google-chrome firebug

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

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

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

您会注意到,在上述两种情况下,我都没有提到如果检查的资源不存在会发生什么。这是我的问题。我在various other places中读到,客户端检查资源是否存在的正确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接口吗?

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

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

4 个答案:

答案 0 :(得分:4)

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

  

404表示服务器无法将客户端的URI映射到a   资源。 [...] 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以查看任务的状态。任务完成后,资源的表示将可用。

答案 1 :(得分:2)

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

我用:

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

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

或许,在您的情况下,您可以考虑搜索。 使用资源集合上的查询参数进行搜索

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

答案 2 :(得分:2)

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

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

浏览器设计用于处理HTTP规范并显示错误是真正的响应(非常有用)。但是,您需要将您的Javascript代码视为与浏览器不同的实体。所以你有你的Javascript REST客户端知道服务是什么样的,浏览器对你的服务有点愚蠢。

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

答案 3 :(得分:0)

当资源不存在时,我只见过GET / HEAD请求返回404(Not Found)。我想如果你试图获得一个资源的状态,头部请求就可以了,因为它不应该返回资源的主体。通过这种方式,您可以区分尝试检索资源的请求和尝试检查其存在的请求。

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

编辑:我记得通过在原始请求中添加一个表示服务器应该如何处理404错误的标题来阅读有关替代解决方案的内容。与200响应的线条,但空洞的身体。