jjzjj

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

coder 2024-12-11 原文

我正在尝试确定 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 header ,而是创建您自己的协议(protocol),通过该协议(protocol)您在正文中返回信息,告诉您您想知道什么,并始终返回 HTTP 200 以关闭浏览器.这是对 SOAP 的主要批评——它试图“绕过”HTTP 而不是充分利用它。根据这一原则,为什么需要返回 404 状态代码?您总是可以返回 200 - 当然,200 表示资源的状态信息可用,状态信息告诉您您真正想知道的内容 - 未找到资源。当然,RESTful 方式应该是返回 404 状态代码。

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

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

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

最佳答案

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

404 indicates that the server can’t map the client’s URI to a resource. [...] A web service may use a 404 response as a signal to the client that the URI is “free”; the client can then create a new resource by sending a PUT request to that URI. Remember that a 404 may be a lie to cover up a 403 or 401. It might be that the resource exists, but the server doesn’t want to let the client know about it.



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

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

HTTP has a synchronous request-response model. The client opens an Internet socket to the server, makes its request, and keeps the socket open until the server has sent the response. [...]

The problem is not all operations can be completed in the time we expect an HTTP request to take. Some operations take hours or days. An HTTP request would surely be timed out after that kind of inactivity. Even if it didn’t, who wants to keep a socket open for days just waiting for a server to respond? Is there no way to expose such operations asynchronously through HTTP?

There is, but it requires that the operation be split into two or more synchronous requests. The first request spawns the operation, and subsequent requests let the client learn about the status of the operation. The secret is the status code 202 (“Accepted”).



所以你可以做 POST /videos创建视频编码任务。该服务将接受该任务,回答 202 并提供一个指向描述任务状态的资源的链接。
202 Accepted
Location: http://tasks.example.com/video/task45543

客户端可以查询此 URI 以查看任务的状态。一旦任务完成,资源的表示将变得可用。

关于javascript - 检查客户端是否可以访问资源的 RESTful 方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10259560/

有关javascript - 检查客户端是否可以访问资源的 RESTful 方法是什么?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  7. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  8. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  9. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  10. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

随机推荐