浏览器是否可以缓存307 Temporary Redirect重定向响应?
问题详情
我搭建了一个简单服务,所有请求都会返回307 Temporary Redirect状态码,重定向到另一个URL。用curl测试的响应内容如下:
curl localhost:8081 -v * Trying 127.0.0.1:8081... * Connected to localhost (127.0.0.1) port 8081 (#0) > POST / HTTP/1.1 > Host: localhost:8081 > User-Agent: curl/8.0.1 > Accept: */* > < HTTP/1.1 307 Temporary Redirect < location: http://localhost:8080 < cache-control: private, max-age=60 < access-control-allow-credentials: true < vary: origin < vary: access-control-request-method < vary: access-control-request-headers < content-length: 0 < date: Wed, 30 Aug 2023 17:41:17 GMT
按照RFC9111的规定,浏览器应该根据cache-control头里的max-age=60缓存这个重定向响应,但实际测试时,浏览器每次都会先请求原URL,再发起重定向后的请求(CORS导致的预检请求不在讨论范围内)。
我在Chrome和Firefox上用这段代码测试:
const options = { cache: 'force-cache', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"some":"data"}' // 修正了原代码的引号语法错误 }; for (let step = 0; step < 1000; step++) { fetch('http://localhost:8081/', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); }
问题原因
307重定向的缓存限制:虽然RFC9111允许缓存3xx重定向,但浏览器对POST请求触发的307重定向有特殊处理逻辑。307要求浏览器保留原请求的方法和请求体转发到目标URL,出于安全和语义一致性的考虑,多数浏览器默认不会缓存这类带请求体的重定向,即使设置了
max-age。Vary头的影响:响应里的
vary: origin, access-control-request-method, access-control-request-headers意味着缓存会严格匹配这些请求头的值。如果每次请求的origin或其他Vary指定的头存在差异(比如跨域场景下的头变化),缓存就会失效,浏览器只能重新发起请求。Fetch cache参数的实际行为:
cache: 'force-cache'会优先尝试使用缓存,但如果缓存不符合条件(比如Vary不匹配、缓存过期,或者浏览器判定该响应不可缓存),还是会发起网络请求。
解决建议
替换为302状态码(非POST场景适用):如果业务允许改变请求方法(302会把POST转为GET),可以改用302 Found,浏览器对302的缓存支持更普遍。但如果必须保留POST方法,这个方案不适用。
补充Expires头增强兼容:部分旧浏览器对
max-age的支持可能有差异,同时设置Expires头(比如Expires: Wed, 30 Aug 2023 17:42:17 GMT,即当前时间加60秒),可以提升缓存的兼容性。精简Vary头:如果不需要区分不同的
origin或请求方法,可精简Vary头,只保留必要字段,或者移除不必要的项,减少缓存不命中的概率。前端优化请求频率:这不是缓存问题的根本解决办法,但可以通过前端防抖、节流,或者合并重复请求,减少发起请求的次数,避免不必要的重定向。
内容的提问来源于stack exchange,提问作者Vladimir

