If-Unmodified-Since 是「这段时间之后没改过,你才能动它」。改过就回 412。
语义和 If-Modified-Since 正好相反。
上一节是读场景的降级,这一节是写场景的时间版,和 6.4.9 的 If-Match 是一对:一个用时间,
一个用标签。
一、两个字段,语义刚好相反
| 字段 | 条件成立时 | 不成立时 | 典型场景 |
|---|---|---|---|
If-Modified-Since |
没改过 → 304 | 改过 → 200 全量 | 读 |
If-Unmodified-Since |
没改过 → 执行 | 改过 → 412 | 写/删 |
记法:带 Un 的是「没改过才允许」,不带的是「改过才给我新的」。一个守门,一个送新。 |
|||
| Demo 里不带条件直接放行(204),带最新时间放行(204),带前一天的时间就 412, | |||
| 正文是「资源已经变了,请重新读一遍」。 |
二、为什么写场景需要它
典型的例子是删除。用户看到一个列表,点了删除某一行。
但如果这期间那一行已经被别人改过,直接删掉可能是错的——也许它已经变成了别的东西。
加上这个条件,服务端就会回 412 让用户先刷新,确认了再删。
这就是「乐观并发控制」:不锁,但提交时检查版本。
另一个场景是覆盖式更新(PUT 整个资源)。如果客户端读到的是旧版,直接 PUT 会把别人的修改冲掉。
这和 6.4.9 说的丢失更新是同一个问题。
三、为什么不推荐用它代替 If-Match
因为它只有秒级精度。两个人如果在同一秒内各改一次,时间戳看起来一样,检查就失效了。
而 If-Match 用 ETag,可以精确到字节。
所以严格场景应该用 If-Match,If-Unmodified-Since 只是给「只有时间戳可用」的老系统兜底。
还有一个细节:这两个字段之间的优先级,
规范和 If-None-Match/If-Modified-Since 那一对不同——那对是 ETag 优先,
而这一对按 RFC 7232 也是 ETag 优先。所以两者都出现时,服务端该只看 If-Match。
四、动手 Demo:三种条件,看什么时候被 412 挡住
服务端资源最后修改时间写死。 客户端分别不带条件、带最新时间、带前一天的时间去发 DELETE,看各自的判定。
ius = hd.get(u'if-unmodified-since', u'')
if ius and ius != LM:
return reply(u'HTTP/1.1 412 Precondition Failed',
[(u'Last-Modified', LM)],
u'资源已经变了,请重新读一遍'.encode(u'utf-8'))
return reply(u'HTTP/1.1 204 No Content', [], b'')
实跑输出:
--------------------------------------------------------------------
If-Unmodified-Since:改过就拒绝
--------------------------------------------------------------------
资源最后修改 Sat, 24 Oct 2026 12:00:00 GMT
【不带条件】
If-Unmodified-Since (没发)
结果 HTTP/1.1 204 No Content | 判定:放行
【带最新时间】
If-Unmodified-Since Sat, 24 Oct 2026 12:00:00 GMT
结果 HTTP/1.1 204 No Content | 判定:放行
【带旧时间】
If-Unmodified-Since Fri, 23 Oct 2026 12:00:00 GMT
结果 HTTP/1.1 412 Precondition Failed | 判定:412 拒绝:资源在这之后改过
正文 资源已经变了,请重新读一遍
它和 `If-Modified-Since` 正好是反的:
前者是「**没改过**才让我干」,后者是「**改过**才给我新内容」。
典型用法是删除或覆盖:客户端读到一个旧版本,
如果这期间别人改过,就不该让这次删除生效。
和 `If-Match` 比,它弱一些——时间精度只到秒,
所以严格的场景应该用 `If-Match` 配 ETag。
不带条件:204 No Content,判定「放行」。204 是「办好了但没内容要回」,删除成功用它最合适。
带最新时间:同样 204 放行。条件成立。
带前一天的时间:412,正文「资源已经变了,请重新读一遍」。
服务端还回了 Last-Modified,让客户端能知道当前版本。
注意这三组都用了 DELETE 方法,但响应里都不带正文——除了那个 412 带了说明文字。
30 秒实验
- 把 DELETE 换成 PUT,看语义上有没有区别。
- 同时发
If-Match和If-Unmodified-Since且两者矛盾,看服务端该听谁。 - 想一想:如果客户端不带任何条件就发 DELETE,服务端该不该拦?
常见误区
- 「它和
If-Modified-Since是一回事」——语义正好相反。 - 「不成立时回 304」——回 412。
- 「它比
If-Match更好因为更简单」——精度只有秒,严格场景不够用。
自测三问(点开对答案)
1. `If-Unmodified-Since` 条件不成立时回什么? —— 412 Precondition Failed。 2. 它和 `If-Modified-Since` 的语义差别在哪? —— 前者是「没改过才允许执行」,后者是「改过才给我新内容」。 3. 为什么严格场景该用 `If-Match`? —— ETag 没有秒级精度问题,能精确到字节。五个条件字段全部讲完。下一个是给排查用的:限制转发跳数。
- ☐ (本节完,下一节 6.4.14 Max-Forwards)