什么是 HTTP PUT 中的幂等性?我可以禁止覆盖资源吗?
What is idempotency in HTTP PUT? Can I disallow overwriting of a resource?
我正在编写一个 REST API,我希望允许具有适当权限的经过身份验证的用户通过此 API 上传文件。我想我会使用 PUT
端点来处理这个问题。我想包括一个故障保护,如果资源已经存在并且用户没有通过查询指定资源应该被覆盖(即 PUT https://my.server.com/api/files/path/to/file.txt?overwrite=1
),请求将被拒绝并出现 400
系列错误.
The HTTP/1.1 RFC documentation of PUT表示允许这样的场景:
If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request. If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be given that reflects the nature of the problem.
但我对幂等性的概念很着迷。 The spec says:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.
However, it is possible that a sequence of several requests is non- idempotent, even if all of the methods executed in that sequence are idempotent. (A sequence is idempotent if a single execution of the entire sequence always yields a result that is not changed by a reexecution of all, or part, of that sequence.) For example, a sequence is non-idempotent if its result depends on a value that is later modified in the same sequence.
A sequence that never has side effects is idempotent, by definition (provided that no concurrent operations are being executed on the same set of resources).
我无法解决这个问题,因为它适用于我的场景。如果 PUT https://my.server.com/myfile.txt
returns 一个 201 Created
第一次是 运行,那么一个 403 Forbidden
或 409 Conflict
错误,而无需在后续请求上做任何其他事情因为文件已经存在,是否违反了幂等性的概念?是否必须将查询添加到 URI 以绕过故障保护违反幂等性?
这是一个常见的幂等性思维错误。
规则的重点不是多个相同的请求得到相同的响应。
规则的要点是,如果多次发送相同的请求,服务器的状态与只发送一次的状态相同。
因此,如果您两次发送相同的请求,第二次将出错并被忽略,但服务器上的状态仍然与您只发送第一次相同。
虽然更新后的 HTTP 标准有一个 interesting note:
An origin server MUST NOT perform the requested method if a received
If-Match condition evaluates to false; instead, the origin server
MUST respond with either a) the 412 (Precondition Failed) status code
or b) one of the 2xx (Successful) status codes if the origin server
has verified that a state change is being requested and the final
state is already reflected in the current state of the target
resource (i.e., the change requested by the user agent has already
succeeded, but the user agent might not be aware of it, perhaps
because the prior response was lost or a compatible change was made
by some other user agent). In the latter case, the origin server
MUST NOT send a validator header field in the response unless it can
verify that the request is a duplicate of an immediately prior change
made by the same user agent.
即使该段落特定于使用 If-Match
header,它也可能适用于此。如果您可以检测到发送了完全相同的请求,也许您只想 return 201 Created
。不过,这有点 off-topic 你的问题。
顺便说一句,你应该使用条件header而不是?overwrite=1
。如果您明确不想允许客户端更新已创建的资源,则客户端可以简单地包括:
If-None-Match: *
然后您的服务器可以 return 412 Precondition Failed
,向客户端发送信号,告知该资源是较早创建的。此外,如果您想强制客户端始终包含此 header,您可以使用 428 Precondition Required
告诉客户端。
我正在编写一个 REST API,我希望允许具有适当权限的经过身份验证的用户通过此 API 上传文件。我想我会使用 PUT
端点来处理这个问题。我想包括一个故障保护,如果资源已经存在并且用户没有通过查询指定资源应该被覆盖(即 PUT https://my.server.com/api/files/path/to/file.txt?overwrite=1
),请求将被拒绝并出现 400
系列错误.
The HTTP/1.1 RFC documentation of PUT表示允许这样的场景:
If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request. If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be given that reflects the nature of the problem.
但我对幂等性的概念很着迷。 The spec says:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.
However, it is possible that a sequence of several requests is non- idempotent, even if all of the methods executed in that sequence are idempotent. (A sequence is idempotent if a single execution of the entire sequence always yields a result that is not changed by a reexecution of all, or part, of that sequence.) For example, a sequence is non-idempotent if its result depends on a value that is later modified in the same sequence.
A sequence that never has side effects is idempotent, by definition (provided that no concurrent operations are being executed on the same set of resources).
我无法解决这个问题,因为它适用于我的场景。如果 PUT https://my.server.com/myfile.txt
returns 一个 201 Created
第一次是 运行,那么一个 403 Forbidden
或 409 Conflict
错误,而无需在后续请求上做任何其他事情因为文件已经存在,是否违反了幂等性的概念?是否必须将查询添加到 URI 以绕过故障保护违反幂等性?
这是一个常见的幂等性思维错误。
规则的重点不是多个相同的请求得到相同的响应。
规则的要点是,如果多次发送相同的请求,服务器的状态与只发送一次的状态相同。
因此,如果您两次发送相同的请求,第二次将出错并被忽略,但服务器上的状态仍然与您只发送第一次相同。
虽然更新后的 HTTP 标准有一个 interesting note:
An origin server MUST NOT perform the requested method if a received If-Match condition evaluates to false; instead, the origin server MUST respond with either a) the 412 (Precondition Failed) status code or b) one of the 2xx (Successful) status codes if the origin server has verified that a state change is being requested and the final state is already reflected in the current state of the target resource (i.e., the change requested by the user agent has already succeeded, but the user agent might not be aware of it, perhaps because the prior response was lost or a compatible change was made by some other user agent). In the latter case, the origin server MUST NOT send a validator header field in the response unless it can verify that the request is a duplicate of an immediately prior change made by the same user agent.
即使该段落特定于使用 If-Match
header,它也可能适用于此。如果您可以检测到发送了完全相同的请求,也许您只想 return 201 Created
。不过,这有点 off-topic 你的问题。
顺便说一句,你应该使用条件header而不是?overwrite=1
。如果您明确不想允许客户端更新已创建的资源,则客户端可以简单地包括:
If-None-Match: *
然后您的服务器可以 return 412 Precondition Failed
,向客户端发送信号,告知该资源是较早创建的。此外,如果您想强制客户端始终包含此 header,您可以使用 428 Precondition Required
告诉客户端。