HTTPQUERY
English

409 Conflict

用法

收到 409 Conflict 错误时,请求本身是有效的,但由于状态不匹配而无法完成。例如,客户端回复了一个已被删除的帖子,目标资源已不再处于兼容状态。服务器返回此状态以示冲突。

注意

409 Conflict 意味着请求格式正确,但与当前资源状态冲突(并发更新、重复创建)。422 Unprocessable Content 意味着请求体语法有效但语义无效(未通过校验规则)。400 Bad Request 意味着请求本身畸形(消息体无法解析、头无效)。409 关乎状态冲突,422 关乎校验,400 关乎语法。

客户端应当检查消息体以确定如何解决问题。在回复已删除帖子的情形中,客户端可选择放弃请求、恢复已删除的原帖,或引用原文创建一个新帖。此操作完全由客户端负责,遵循服务器设定的要求或策略。

SEO 影响

像 Google 这样的搜索引擎不会索引返回 409 状态的 URL。此前已被索引、如今返回该状态码的 URL 会从搜索结果中移除。

示例

客户端尝试为一篇 “ID = 111” 的现有博客帖子添加一个 “like” 标签。服务器作出响应,表明该帖子已被冻结,不再接受回复或标签。

请求

POST /blog/update?postid=111&flag=like HTTP/1.1
Host: example.com

响应

HTTP/1.1 409 Conflict
Content-Type: text/html
Content-Length: 288

<html>
  <head>
    <title>Blog Entry Frozen</title>
  </head>
  <body>
    <p>This post has been marked read-only. To post
    a reply or tag, change the status and try
    again.</p>
  </body>
</html>

如何修复

409 Conflict 意味着请求与服务器上资源的当前状态冲突。

在重试前获取当前的资源状态。发送 GET 请求以获取最新版本。自客户端上次读取数据以来,资源状态已发生变化。将返回的 ETag 或版本字段与客户端持有的值进行比较。

使用条件头来检测冲突。在 PUT 和 PATCH 请求中包含带当前 ETag 值的 If-Match。当 ETag 不再匹配时,服务器会拒绝请求,从而防止盲目覆盖。这种模式称为乐观并发控制。

PUT /api/resource/42 HTTP/1.1
If-Match: "abc123"
Content-Type: application/json

{"name": "updated value"}

当另一个客户端在 GET 与 PUT 之间修改了资源时,服务器返回 409。

合并变更或实现冲突解决逻辑。将客户端预期的变更与当前的服务器状态进行比较。应用合并策略:后写入者获胜、字段级合并,或提示终端用户解决差异。在载荷中带有 version 或 revision 字段的 API,要求客户端在更新请求中包含当前版本号。

解决重复资源冲突。使用 POST 或 PUT 创建资源时,若已存在具有相同唯一标识符的资源,服务器返回 409。在创建前检查现有条目,并使用幂等键以避免重试时的重复创建。

处理数据库级别的冲突。当唯一约束、外键约束或行级锁阻止操作时,由数据库支撑的应用服务器返回 409。响应体通常包含具体的约束名称。在重试前解决底层的数据冲突(重复键、缺失父记录、并发事务)。

对于版本控制系统,拉取最新版本并重新应用变更。获取最新修订、协调差异并重新提交更新。基于 Git 的 API(GitHub、GitLab)在推送与上游变更冲突时返回 409。

检查响应体中的冲突细节。服务器通常会包含解释不匹配的信息:冲突的字段、当前值或期望的版本。使用这些数据来确定正确的解决路径。

实现带状态刷新的重试逻辑。对于自动化客户端,构建一个重试循环:获取最新的资源状态、重新应用预期的修改,并重新提交。添加指数退避,以避免在高并发条件下压垮服务器。

代码参考

.NET

HttpStatusCode.Conflict

Rust

http::StatusCode::CONFLICT

Rails

:conflict

Go

http.StatusConflict

Symfony

Response::HTTP_CONFLICT

Python3.5+

http.HTTPStatus.CONFLICT

Java

java.net.HttpURLConnection.HTTP_CONFLICT

Apache HttpComponents Core

org.apache.hc.core5.http.HttpStatus.SC_CONFLICT

Angular

@angular/common/http/HttpStatusCode.Conflict