浏览器(Chrome / Firefox)不会将 PATCH 请求中的 If-Match 请求标头发送到已缓存的资源。
我制作了一个带有 2 个按钮的测试网页,一个用于 GET 请求,另一个用于 PATCH 以及使用 Fetch API 发送请求的脚本。
document.getElementById('get-btn').addEventListener('click', async () => {
await fetch("http://test.local/api/v1/test", {
method: 'GET',
headers: {
'Accept': 'application/hal+json',
'Authorization': 'Bearer XXXXX',
}
});
});
document.getElementById('patch-btn').addEventListener('click', async () => {
await fetch("http://test.local/api/v1/test", {
method: 'PATCH',
headers: {
'Accept': 'application/hal+json',
'Authorization': 'Bearer XXXXX',
'Content-Type': 'application/json'
},
body: JSON.stringify({})
});
});
API 端点始终为 GET 方法返回 Etag 响应标头。 Etag 值是一些 md5 哈希值(例如“ffsd8fsd9adsf”)。 测试场景:
注意:Access-Control-Allow-Headers 允许 If-Match。
现在,我的问题:是我负责在 PATCH 请求中发送 If-Match 请求标头,还是我缺少一些阻止浏览器以自动添加 If- 的方式添加 If-Match 请求标头的内容GET 请求无匹配?
如果我有责任包含 If-Match 标头,那么对于浏览器将 If-None-Match 添加到 GET 请求但不将 If-Match 添加到 PATCH 请求的不一致行为的解释是什么?
您(而不是浏览器)负责发送
If-Match
标头。因为要不要这样做是一个应用逻辑的问题。
PATCH标准提到了这一点(对于
PUT
和POST
也是如此):
PATCH 请求可以以幂等的方式发出, 这也有助于防止两个人之间的碰撞产生不良后果 在相似的时间范围内对同一资源发出 PATCH 请求...使用此类补丁应用程序的客户端应该使用条件请求 如果资源已更新,请求将失败 自客户端上次访问资源以来。例如,客户 可以在 PATCH 上的 If-Match 标头中使用强 ETag 请求。
也有补丁格式不需要从操作的情况 已知的基点(例如,将文本行附加到日志文件,或非 行与数据库表发生冲突),在这种情况下,同样需要注意 不需要客户请求。
浏览器不知道你有什么样的应用程序,所以仅仅因为它有当前 ETag 的记录就自动添加 header 是不合适的。
相比之下,
If-None-Match
背后的条件请求逻辑与应用程序逻辑无关;这只是性能增强。如果条件请求成功,则客户端已经拥有服务器本应发送的相同资源,因此没有理由再次发送它。因此浏览器为您处理这个问题是安全的。