I'm trying to determine the best practice in a REST API for determining whether the client can access a particular resource. Two quick example scenarios:
我正在尝试确定REST API中的最佳实践,以确定客户端是否可以访问特定资源。两个快速示例场景:
A phone directory lookup service. Client looks up a phone number by accessing eg.GET http://host/directoryEntries/numbers/12345
... where 12345
is the phone number to try and find in the directory. If it exists, it would return information like the name and address of the person whose phone number it is.
电话目录查找服务。客户通过访问例如查找电话号码。 GET http:// host / directoryEntries / numbers / 12345 ...其中12345是在目录中尝试查找的电话号码。如果存在,它将返回诸如电话号码的人的姓名和地址之类的信息。
A video format shifting service. Client submits a video in one format to eg.POST http://host/videos/
... and receives a 'video GUID' which has been generated by the server for this video. Client then checks eg.GET http://host/videos/[GUID]/flv
... to get the video, converted into the FLV format, if the converted version exists.
视频格式转换服务。客户端以一种格式提交视频,例如。 POST http:// host / videos / ...并接收服务器为此视频生成的“视频GUID”。客户然后检查例如。 GET http:// host / videos / [GUID] / flv ...获取视频,如果转换后的版本存在,则转换为FLV格式。
You'll notice that in both cases above, I didn't mention what should happen if the resource being checked for doesn't exist. That's my question here. I've read in various other places that the proper RESTful way for the client to check whether the resource exists here is to call HEAD
(or maybe GET
) on the resource, and if the resource doesn't exist, it should expect a 404 response. This would be fine, except that a 404 response is widely considered an 'error'; the HTTP/1.1 spec states that the 4xx class of status code is intended for cases in which the client 'seems to have erred'. But wait; in these examples, the client has surely not erred. It expects that it may get back a 404 (or others; maybe a 403 if it's not authorized to access this resource), and it has made no mistake whatsoever in requesting the resource. The 404 isn't intended to indicate an 'error condition', it is merely information - 'this does not exist'.
您会注意到,在上述两种情况下,我都没有提到如果检查的资源不存在会发生什么。这是我的问题。我在其他各个地方读过,客户端检查资源是否存在的正确RESTful方式是在资源上调用HEAD(或者可能是GET),如果资源不存在,则应该期望404响应。这很好,除了404响应被广泛认为是'错误'; HTTP / 1.1规范声明4xx类状态代码适用于客户端“似乎有错误”的情况。可是等等;在这些例子中,客户肯定没有错。它期望它可以返回404(或其他;如果它没有被授权访问该资源,则可能是403),并且它在请求资源时没有任何错误。 404并不是为了表示“错误条件”,它只是信息 - “这不存在”。
And browsers behave, as the HTTP spec suggests, as if the 404 response is a genuine error. Both Google Chrome and Firebug's console spew out a big red "404 Not Found" error message into the Javascript console each time a 404 is received by an XHR request, regardless of whether it was handled by an error handler or not, and there is no way to disable it. This isn't a problem for the user, as they don't see the console, but as a developer I don't want to see a bunch of 404 (or 403, etc.) errors in my JS console when I know perfectly well that they aren't errors, but information being handled by my Javascript code. It's line noise. In the second example I gave, it's line noise to the extreme, because the client is likely to be polling the server for that /flv
as it may take a while to compile and the client wants to display 'not compiled yet' until it gets a non-404. There may be a 404 error appearing in the JS console every second or two.
正如HTTP规范所暗示的那样,浏览器的行为就像404响应是真正的错误一样。每当XHR请求收到404时,Google Chrome和Firebug的控制台都会向Javascript控制台发出一条红色的“404 Not Found”错误消息,无论是否由错误处理程序处理,并且没有禁用它的方法。这对用户来说不是问题,因为他们没有看到控制台,但作为开发人员,当我完全了解时,我不希望在我的JS控制台中看到一堆404(或403等)错误以及它们不是错误,而是由我的Javascript代码处理的信息。这是线路噪音。在我给出的第二个例子中,它的线路噪声到了极端,因为客户端可能正在为该/ flv轮询服务器,因为它可能需要一段时间来编译并且客户端想要显示“尚未编译”直到它获得非404。每隔一秒或两秒,JS控制台中可能会出现404错误。
So, is this the best or most proper way we have with REST to check for the existence of a resource? How do we get around the line noise in the JS console? It may well be suggested that, in my second example, a different URI could be queried to check the status of the compilation, like:GET http://host/videos/[GUID]/compileStatus
... however, this seems to violate the REST principle a little, to me; you're not using HTTP to its full and paying attention to the HTTP headers, but instead creating your own protocol whereby you return information in the body telling you what you want to know instead, and always return an HTTP 200 to shut the browser up. This was a major criticism of SOAP - it tries to 'get around' HTTP rather than use it to its full. By this principle, why does one ever need to return a 404 status code? You could always return a 200 - of course, the 200 is indicating that the a resource's status information is available, and the status information tells you what you really wanted to know - the resource was not found. Surely the RESTful way should be to return a 404 status code.
那么,这是我们使用REST检查资源是否存在的最佳或最恰当的方式?我们如何绕过JS控制台中的线路噪音?可以建议,在我的第二个示例中,可以查询不同的URI来检查编译的状态,例如:GET http:// host / videos / [GUID] / compileStatus ...但是,这似乎是对我来说,违反了REST原则;你没有完全使用HTTP并关注HTTP标头,而是创建自己的协议,然后在正文中返回信息,告诉你你想知道什么,并且总是返回HTTP 200以关闭浏览器。这是对SOAP的一个主要批评 - 它试图“绕过”HTTP而不是充分利用它。根据这个原则,为什么需要返回404状态代码?您总是可以返回200 - 当然,200表示资源的状态信息可用,状态信息告诉您您真正想知道的内容 - 找不到资源。当然,RESTful方式应该是返回404状态代码。
This mechanism seems even more contrived if we apply it to the first of my above examples; the client would perhaps query:GET http://host/directoryEntries/numberStatuses/12345
... and of course receive a 200; the number 12345
's status information exists, and tells you... that the number is not found in the directory. This would mean that ANY number queried would be '200 OK', even though it may not exist - does this seem like a good REST interface?
如果我们将它应用于上面的第一个例子,这个机制似乎更加人为;客户端可能会查询:GET http:// host / directoryEntries / numberStatuses / 12345 ...当然收到200;数字12345的状态信息存在,并告诉您......在目录中找不到该数字。这意味着查询的任何数字都是'200 OK',即使它可能不存在 - 这看起来像是一个很好的REST接口吗?
Am I missing something? Is there a better way to determine whether a resource exists RESTfully, or should HTTP perhaps be updated to indicate that non-2xx status codes should not necessarily be considered 'errors', and are just information? Should browsers be able to be configured so that they don't always output non-2xx status responses as 'errors' in the JS console?
我错过了什么吗?有没有更好的方法来确定资源是否存在RESTful,或者是否应该更新HTTP以指示非2xx状态代码不一定被视为“错误”,并且只是信息?是否应该配置浏览器,以便它们不总是在JS控制台中输出非2xx状态响应作为“错误”?
PS. If you read this far, thanks. ;-)
PS。如果你读到这里,谢谢。 ;-)
4 个解决方案
#1
2
I think you have changed the semantics of the request. With a RESTful architecture, you are requesting a resource. Therefore requesting a resource that does not exist or not found is considered an error.
我认为你已经改变了请求的语义。使用RESTful架构,您正在请求资源。因此,请求不存在或未找到的资源被视为错误。
I use:
-
404 if
GET http://host/directoryEntries/numbers/12345
does not exist.404如果GET http:// host / directoryEntries / numbers / 12345不存在。
-
400 is actually a bad request
400 Bad Request
400实际上是一个错误的请求400 Bad Request
Perhaps, in your case you could think about searching instead. Searches are done with query parameters on a collection of resources
也许,在你的情况下,你可以考虑搜索。使用资源集合上的查询参数进行搜索
What you want is GET http://host/directoryEntries/numbers?id=1234
Which would return 200 and an empty list if none exist or a list of matches.
你想要的是GET http:// host / directoryEntries / numbers?id = 1234如果不存在则返回200和空列表或匹配列表。
#2
4
It is perfectly okay to use 404 to indicate that resource is not found. Some quotes from the book "RESTful Web Services" (very good book about REST by the way):
使用404表示找不到资源是完全可以的。 “RESTful Web Services”一书中的一些引用(顺便提一下关于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映射到资源。 [...] Web服务可以使用404响应作为向客户端发出URI“空闲”的信号;然后,客户端可以通过向该URI发送PUT请求来创建新资源。请记住,404可能是掩盖403或401的谎言。可能是资源存在,但服务器不希望让客户知道它。
Use 404 when service can't find requested resource, do not overuse to indicate the errors which are actually not relevant to the existence of resource. Also, client may "query" the service to know whether this URI is free or not.
当服务找不到请求的资源时使用404,不要过度使用以指示实际上与资源的存在无关的错误。此外,客户端可以“查询”服务以知道该URI是否空闲。
Performing long-running operations like encoding of video files
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. [...]
HTTP具有同步请求 - 响应模型。客户端打开到服务器的Internet套接字,发出请求,并在服务器发送响应之前保持套接字打开。 [...]
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?
问题不是所有操作都可以在我们期望HTTP请求采取的时间内完成。有些操作需要数小时或数天。在那种不活动之后,HTTP请求肯定会超时。即使它没有,谁想要保持套接字打开几天只是等待服务器响应?是否无法通过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”).
有,但它要求将操作拆分为两个或多个同步请求。第一个请求产生操作,后续请求让客户端了解操作的状态。秘密是状态代码202(“已接受”)。
So you could do POST /videos
to create a video encoding task. The service will accept the task, answer with 202 and provide a link to a resource describing the state of the task.
因此,您可以执行POST /视频来创建视频编码任务。该服务将接受该任务,以202回答并提供指向描述任务状态的资源的链接。
202 Accepted
Location: http://tasks.example.com/video/task45543
Client may query this URI to see the status of the task. Once the task is complete, representation of resource will become available.
客户端可以查询此URI以查看任务的状态。任务完成后,资源的表示将变为可用。
#3
2
IMO the client has indeed erred in requesting a non-existent resource. In both your examples the service can be designed in a different way so an error can be avoided on the client side. For example, in the video conversion service as the GUID has already been assigned, the message body at videos/id can contain a flag indicating whether the conversion was done or not.
IMO客户确实在请求不存在的资源时犯了错误。在您的示例中,可以以不同的方式设计服务,以便在客户端避免错误。例如,在已经分配了GUID的视频转换服务中,videos / id处的消息正文可以包含指示转换是否已完成的标志。
Similarly, in the phone directory example, you are searching for a resource and this can be handled through something like /numbers/?search_number=12345 etc. so that the server returns a list of matching resources which you can then query further.
类似地,在电话目录示例中,您正在搜索资源,这可以通过/ numbers /?search_number = 12345等处理,以便服务器返回匹配资源的列表,然后您可以进一步查询。
Browsers are designed for working with the HTTP spec and showing an error is a genuine response (pretty helpful too). However, you need to think about your Javascript code as a separate entity from the browser. So you have your Javascript REST client which knows what the service is like and the browser which is sort of dumb with regards to your service.
浏览器设计用于处理HTTP规范并显示错误是真正的响应(非常有用)。但是,您需要将您的Javascript代码视为与浏览器不同的实体。所以你有你的Javascript REST客户端知道服务是什么样的,浏览器对你的服务有点愚蠢。
Also, REST is independent of protocols in theory. HTTP happens to be the most common protocol where REST is used. Another example I can think of is Android content providers whose design is RESTful but not dependent on HTTP.
此外,REST在理论上独立于协议。 HTTP恰好是使用REST的最常用协议。我能想到的另一个例子是Android内容提供商,其设计是RESTful但不依赖于HTTP。
#4
0
I've only ever seen GET/HEAD requests return 404 (Not Found) when a resource doesn't exist. I think if you are trying to just get a status of a resource a head request would be fine as it shouldn't return the body of a resource. This way you can differentiate between requests where you are trying to retrieve the resource and requests where you are trying to check for their existance.
当资源不存在时,我只见过GET / HEAD请求返回404(Not Found)。我想如果你试图获得一个资源的状态,头部请求就可以了,因为它不应该返回资源的主体。通过这种方式,您可以区分尝试检索资源的请求和尝试检查其存在的请求。
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Edit: I remember reading about an alternative solution by adding a header to the original request that indicated how the server should handle 404 errors. Something along the lines of responding with 200, but an empty body.
编辑:我记得通过在原始请求中添加标题来阅读有关替代解决方案的内容,该标头指示服务器应如何处理404错误。回应200的东西,但空洞的身体。
#1
2
I think you have changed the semantics of the request. With a RESTful architecture, you are requesting a resource. Therefore requesting a resource that does not exist or not found is considered an error.
我认为你已经改变了请求的语义。使用RESTful架构,您正在请求资源。因此,请求不存在或未找到的资源被视为错误。
I use:
-
404 if
GET http://host/directoryEntries/numbers/12345
does not exist.404如果GET http:// host / directoryEntries / numbers / 12345不存在。
-
400 is actually a bad request
400 Bad Request
400实际上是一个错误的请求400 Bad Request
Perhaps, in your case you could think about searching instead. Searches are done with query parameters on a collection of resources
也许,在你的情况下,你可以考虑搜索。使用资源集合上的查询参数进行搜索
What you want is GET http://host/directoryEntries/numbers?id=1234
Which would return 200 and an empty list if none exist or a list of matches.
你想要的是GET http:// host / directoryEntries / numbers?id = 1234如果不存在则返回200和空列表或匹配列表。
#2
4
It is perfectly okay to use 404 to indicate that resource is not found. Some quotes from the book "RESTful Web Services" (very good book about REST by the way):
使用404表示找不到资源是完全可以的。 “RESTful Web Services”一书中的一些引用(顺便提一下关于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映射到资源。 [...] Web服务可以使用404响应作为向客户端发出URI“空闲”的信号;然后,客户端可以通过向该URI发送PUT请求来创建新资源。请记住,404可能是掩盖403或401的谎言。可能是资源存在,但服务器不希望让客户知道它。
Use 404 when service can't find requested resource, do not overuse to indicate the errors which are actually not relevant to the existence of resource. Also, client may "query" the service to know whether this URI is free or not.
当服务找不到请求的资源时使用404,不要过度使用以指示实际上与资源的存在无关的错误。此外,客户端可以“查询”服务以知道该URI是否空闲。
Performing long-running operations like encoding of video files
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. [...]
HTTP具有同步请求 - 响应模型。客户端打开到服务器的Internet套接字,发出请求,并在服务器发送响应之前保持套接字打开。 [...]
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?
问题不是所有操作都可以在我们期望HTTP请求采取的时间内完成。有些操作需要数小时或数天。在那种不活动之后,HTTP请求肯定会超时。即使它没有,谁想要保持套接字打开几天只是等待服务器响应?是否无法通过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”).
有,但它要求将操作拆分为两个或多个同步请求。第一个请求产生操作,后续请求让客户端了解操作的状态。秘密是状态代码202(“已接受”)。
So you could do POST /videos
to create a video encoding task. The service will accept the task, answer with 202 and provide a link to a resource describing the state of the task.
因此,您可以执行POST /视频来创建视频编码任务。该服务将接受该任务,以202回答并提供指向描述任务状态的资源的链接。
202 Accepted
Location: http://tasks.example.com/video/task45543
Client may query this URI to see the status of the task. Once the task is complete, representation of resource will become available.
客户端可以查询此URI以查看任务的状态。任务完成后,资源的表示将变为可用。
#3
2
IMO the client has indeed erred in requesting a non-existent resource. In both your examples the service can be designed in a different way so an error can be avoided on the client side. For example, in the video conversion service as the GUID has already been assigned, the message body at videos/id can contain a flag indicating whether the conversion was done or not.
IMO客户确实在请求不存在的资源时犯了错误。在您的示例中,可以以不同的方式设计服务,以便在客户端避免错误。例如,在已经分配了GUID的视频转换服务中,videos / id处的消息正文可以包含指示转换是否已完成的标志。
Similarly, in the phone directory example, you are searching for a resource and this can be handled through something like /numbers/?search_number=12345 etc. so that the server returns a list of matching resources which you can then query further.
类似地,在电话目录示例中,您正在搜索资源,这可以通过/ numbers /?search_number = 12345等处理,以便服务器返回匹配资源的列表,然后您可以进一步查询。
Browsers are designed for working with the HTTP spec and showing an error is a genuine response (pretty helpful too). However, you need to think about your Javascript code as a separate entity from the browser. So you have your Javascript REST client which knows what the service is like and the browser which is sort of dumb with regards to your service.
浏览器设计用于处理HTTP规范并显示错误是真正的响应(非常有用)。但是,您需要将您的Javascript代码视为与浏览器不同的实体。所以你有你的Javascript REST客户端知道服务是什么样的,浏览器对你的服务有点愚蠢。
Also, REST is independent of protocols in theory. HTTP happens to be the most common protocol where REST is used. Another example I can think of is Android content providers whose design is RESTful but not dependent on HTTP.
此外,REST在理论上独立于协议。 HTTP恰好是使用REST的最常用协议。我能想到的另一个例子是Android内容提供商,其设计是RESTful但不依赖于HTTP。
#4
0
I've only ever seen GET/HEAD requests return 404 (Not Found) when a resource doesn't exist. I think if you are trying to just get a status of a resource a head request would be fine as it shouldn't return the body of a resource. This way you can differentiate between requests where you are trying to retrieve the resource and requests where you are trying to check for their existance.
当资源不存在时,我只见过GET / HEAD请求返回404(Not Found)。我想如果你试图获得一个资源的状态,头部请求就可以了,因为它不应该返回资源的主体。通过这种方式,您可以区分尝试检索资源的请求和尝试检查其存在的请求。
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Edit: I remember reading about an alternative solution by adding a header to the original request that indicated how the server should handle 404 errors. Something along the lines of responding with 200, but an empty body.
编辑:我记得通过在原始请求中添加标题来阅读有关替代解决方案的内容,该标头指示服务器应如何处理404错误。回应200的东西,但空洞的身体。