Content-Location 说明「你手上这份内容,老家在另一个地址」。
它和 Location 只差一个词,但不会让客户端再发一次请求。
上一节定了正文边界,这一节说正文的「来历」。6.5.4 讲 Location 时留的对照,到这里补上。
一、它说的是「内容的地址」
请求 /report-copy 拿到 200 和完整正文,首部里写 Content-Location: /report,
意思是「内容给你了,它正经的地址是 /report」。
关键点:客户端不会因此去请求 /report。
这是它和 Location 的根本区别——后者配 3xx 时是命令「去那儿」,前者只是备注「它老家在那儿」。
Demo 里三次请求都是一次往返:/report 200、/report-copy 200 带 Content-Location、
/alias 302 带 Location。只有第三个需要再发一次。
二、Location 与 Content-Location
两个首部只差一个词,行为差一次往返:
| 首部 | 含义 | 客户端会再请求吗 |
|---|---|:---:|
| Location | 你走错了,去那儿 | 会(配 3xx 时) |
| Content-Location | 东西给你了,它老家在那儿 | 不会 |
同一个 Location 在 201 里又变成「新资源在这儿」,也不触发请求。
所以判断依据永远是状态码,不是首部名。
实践中最常见的误用,是把 Location 当 Content-Location 用:以为加了它客户端就会跳转,
结果什么都没发生。
三、实际用在哪
用处确实不多。
最典型的是同一份内容有多个入口:带版本号的 URL(/v2/report 与 /report 内容相同)、
镜像地址、内容协商后的具体版本。
另一处是 PUT:上传成功后回一份内容,用 Content-Location 说明「这就是 /a 那份的副本」,
客户端不用再 GET 一次。
它还能帮缓存做去重:两个 URL 内容相同,缓存看到同一个 Content-Location 就可以只存一份。
不过这属于优化,实现里很少做。
四、动手 Demo:同一个首部位置,两种行为
服务端准备三个入口:正主 /report、副本 /report-copy、跳转 /alias。
看客户端在这三种情况下分别发了几个请求。
def fn(raw, st):
path = raw.split(b' ')[1].decode('latin-1')
if path == u'/report':
return X.reply(u'HTTP/1.1 200 OK', [(u'Content-Type', u'text/html')], DOC)
if path == u'/report-copy':
return X.reply(u'HTTP/1.1 200 OK',
[(u'Content-Type', u'text/html'),
(u'Content-Location', u'/report')], DOC)
return X.reply(u'HTTP/1.1 302 Found', [(u'Location', u'/report')], b'moved')
实跑输出:
--------------------------------------------------------------------
Content-Location:这份内容的老家在哪儿
--------------------------------------------------------------------
请求 状态 首部里多了什么
/report HTTP/1.1 200 OK (没有)
/report-copy HTTP/1.1 200 OK Content-Location: /report
/alias HTTP/1.1 302 Found Location: /report
三次都只发了一次请求。`/report-copy` 拿到 200 和完整正文,
但首部多出一行 `Content-Location: /report`,意思是「你手上这份内容,
正经的地址是 /report」。客户端**不会**因此去请求 /report。
对照 `/alias`:那是 302 加 `Location`,客户端得再发一次才拿到东西。
两个首部只差一个词,行为差一次往返:
Location 你走错了,去那儿(要再请求)
Content-Location 东西给你了,它老家在那儿(不再请求)
实际用途不多,最典型的是同一份内容有多个入口(带版本号的 URL、镜像地址);
或者 PUT 之后回一份内容,说明「这是 /a 那份的副本」。
/report 200,什么都没有——它就是正主。
/report-copy 200,多一行 Content-Location: /report,正文完整。客户端没有再去请求 /report。
/alias 302,带 Location: /report。这才是「去那儿」,需要第二次往返。
三次请求、三次往返的差别,全在这两个首部的名字上。
记法:带 -Location 前缀的是「补充说明」,光秃秃的 Location 是「指令」。
30 秒实验
- 给
/report的响应也加一行Content-Location: /report-copy,想想要不要跟。 - 把
/report-copy改成 301 加Location,看行为变不变。 - 想一想:如果两个 URL 的内容不同,写同一个 Content-Location 会误导谁?
常见误区
- 「Content-Location 会触发跳转」——不会,它只是备注。
- 「它和 Location 可以互换」——一个是指令,一个是说明。
- 「内容不同的两个地址也能共用一个 Content-Location」——那是撒谎,会误导缓存。
自测三问(点开对答案)
1. `Content-Location` 会让客户端再发请求吗? —— 不会,它只说明内容的原始地址。 2. `Location` 在 201 里是什么含义? —— 新建资源的地址,也不触发请求。 3. 什么场景适合用 `Content-Location`? —— 同一份内容有多个入口,或者 PUT 之后说明副本来源。地址说清了,接下来给正文配一个校验和:Content-MD5。
- ☐ (本节完,下一节 6.6.6 Content-MD5)