You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从FastAPI获取文件时如何利用浏览器缓存?

问题核心原因

  • POST请求默认不属于浏览器可缓存的HTTP请求方法范畴,fetch的cache配置项仅对GET、HEAD等标准可缓存请求生效,你通过POST请求传递文件路径的写法本身不符合HTTP缓存的默认规则。
  • URL.createObjectURL()每次调用生成的是独立的临时内存地址,和HTTP响应缓存完全无关,这是表象而非缓存失效的根本原因。
  • 即便响应ETag无变化,若后端没有正确返回Cache-Control、Vary等缓存校验相关的响应头,浏览器也不会触发304协商缓存逻辑。

解决方案

方案1:改为GET请求(推荐,符合HTTP规范,缓存成本最低)

将文件路径编码后作为URL查询参数传递,使用GET请求发起调用,浏览器可直接复用原生HTTP缓存能力:

const fileParam = encodeURIComponent(myFilePathString)
fetch(`/files/?path=${fileParam}`, {
  method: "GET",
  cache: "no-cache"
})
.then(res => res.blob())
.then(blob => {
  myDomElement.src = URL.createObjectURL(blob)
  // 资源不用时调用URL.revokeObjectURL(myDomElement.src)释放内存
})

后端FastAPI侧补充完整缓存相关响应头配置即可:

import os
from fastapi import FastAPI, Request, Response
from fastapi.responses import FileResponse

app = FastAPI()

@app.get("/files/")
async def get_file(path: str, request: Request, response: Response):
    # 计算文件唯一ETag,可根据实际场景调整生成逻辑
    file_stat = os.stat(path)
    etag = f'"{file_stat.st_mtime_ns}-{file_stat.st_size}"'
    # 校验请求的ETag是否匹配
    if_none_match = request.headers.get("if-none-match")
    if if_none_match == etag:
        return Response(status_code=304)
    # 正常返回文件时携带缓存头
    return FileResponse(
        path,
        headers={
            "ETag": etag,
            "Cache-Control": "public, max-age=0"
        }
    )

该方案下ETag不变时浏览器会自动触发304协商缓存,不会重新传输完整文件内容,完全符合你的预期。

方案2:保留POST请求的手动缓存实现

如果业务要求必须用POST传递文件路径,可在前端手动实现缓存逻辑:

// 全局缓存对象,存储文件路径对应的ETag和blob数据
const fileCache = new Map()

fetch('/files/', {
  method: "POST",
  body: JSON.stringify(myFilePathString),
  cache: "no-cache"
})
.then(res => {
  const currentEtag = res.headers.get('ETag')
  const cachedRecord = fileCache.get(myFilePathString)
  // 匹配到有效缓存直接复用,不读取响应体
  if (cachedRecord && cachedRecord.etag === currentEtag) {
    return cachedRecord.blob
  }
  // 无有效缓存则读取响应体并更新缓存
  return res.blob().then(blob => {
    fileCache.set(myFilePathString, {
      etag: currentEtag,
      blob: blob
    })
    return blob
  })
})
.then(blob => {
  myDomElement.src = URL.createObjectURL(blob)
})

该方案下HTTP请求仍会发出,但ETag匹配时可直接复用本地缓存的blob数据,无需重新解析响应内容,也能达到节省资源的效果。

内容的提问来源于stack exchange,提问作者Jürg Schneider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 13:45:03