对于 REST 终结点,开发人员通常希望控制更新是创建新记录还是仅修改现有记录。
If-Match HTTP 标头在数据 API 生成器(DAB)中提供该控件。
默认情况下,DAB 将PUT和PATCH作为更新插入作处理:
如果资源存在:它已更新。
如果不存在,则插入它。
-
PUT→完整插入(替换资源)。 -
PATCH→增量更新插入(应用部分更新)。
-
添加 If-Match: * 此行为以仅更新语义。
DAB 中的 If-Match 用途
If-Match 仅支持通配符值 *。
| 标头值 | 行为 |
|---|---|
If-Match: * |
仅当资源存在时执行更新;如果找不到→ 404,则为 。 |
If-Match: <any other> |
拒绝;400 错误请求 (Etags not supported, use '*')。 |
| (缺席) | Upsert 行为(如果未找到插入,则为更新)。 |
行为概述
- DAB 不实现每条记录 ETag 或版本匹配。
- 不会评估并发令牌。
*仅断言“必须存在”。 - 仅适用于 REST,不适用于 GraphQL。
- 目前对 DELETE作没有意义。
将 If-Match 与 PUT 配合使用
如果没有 If-Match,则 PUT 插入资源不存在时(返回 201 Created)。
仅更新示例
请求
PUT /api/Books/id/1
If-Match: *
Content-Type: application/json
{
"title": "The Return of the King"
}
成功(记录存在)
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"title": "The Return of the King"
}
失败(记录缺失)
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "No Update could be performed, record not found"
}
Upsert 插入示例(不存在 If-Match 和记录)
请求
PUT /api/Books/id/500
Content-Type: application/json
{
"title": "Inserted via PUT",
"publisher_id": 7
}
响应
HTTP/1.1 201 Created
Location: id/500
Content-Type: application/json
{
"id": 500,
"title": "Inserted via PUT",
"publisher_id": 7
}
将 If-Match 与 PATCH 配合使用
PATCH 行为类似。 如果没有 If-Match,它将执行增量更新插入。 使用 If-Match: *时,它只会更新现有行。
请求
PATCH /api/Books/id/1
If-Match: *
Content-Type: application/json
{
"title": "The Two Towers"
}
成功时的响应
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"title": "The Two Towers"
}
找不到响应
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "No Update could be performed, record not found"
}
无效 If-Match 用法
除(包括带引号的字符串)之外 * 的任何值都会被拒绝。
请求
PUT /api/Books/id/1
If-Match: "abc123"
Content-Type: application/json
{
"title": "To Kill a Mockingbird"
}
响应
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Etags not supported, use '*'"
}
Review
- 省略
If-Matchupsert (insert-or-update) 语义。 - 用于
If-Match: *严格的仅更新语义(如果缺少该项的话为 404)。 - 不要使用任何其他值。 未实现真正的 ETag 匹配。