bug: Model profile image 302 redirect is cached by browser (no Cache-Control header) → stale avatar after URL change

用户或管理员通过 Open WebUI 的 API 或 UI 修改了模型的 profile_image_url (如从 https://example.com/a.png 改为 https://example.com/b.png ),之后 同一浏览器标签页 中与该模型对话时,助手头像仍显示旧图片或

快速结论:该问题发生在 Open WebUI 中,当管理员更新模型的头像 URL 后,浏览器仍无限期显示旧头像。优先排查后端是否在 302 响应中添加了 Cache-Control: no-store 头,以及前端是否加入了基于 updated_at 的缓存破坏参数。

问题场景

用户或管理员通过 Open WebUI 的 API 或 UI 修改了模型的 profile_image_url (如从 https://example.com/a.png 改为 https://example.com/b.png ),之后同一浏览器标签页中与该模型对话时,助手头像仍显示旧图片或 favicon.png 回退。仅强制硬刷新(Ctrl+Shift+R)后才能更新。该问题在 Open WebUI v0.10.2 及 main 分支上均可复现,并在 Chrome 和 Firefox 中验证。

报错原文

No explicit error displayed in console / UI.
User observes stale avatar (old profile image or favicon.png fallback) despite model meta.profile_image_url being updated.
DevTools → Network shows the request served from "(disk cache)" or no request at all.

原因分析

后端 backend/open_webui/routers/models.pyget_model_profile_image() 函数返回的四个 302 重定向未设置 Cache-Control 头。根据 RFC 7234 §4.2.2,浏览器允许在无明确指令时按启发式新鲜度缓存 302 响应。Chrome 和 Firefox 实际上会缓存这些响应。同时,前端 src/lib/components/chat/Messages/ResponseMessage.svelte 中头像图片的 src 没有加入缓存破坏参数(如 &v=${model?.info?.updated_at}),导致浏览器对同一 id+lang 的组合复用缓存的旧重定向目标。

需要说明的是,此问题曾被修复(#19959,版本 v0.6.42/v0.6.43 中合并,添加了 Cache-Control: no-cache, must-revalidate),但随后在 v0.7.0 起被刻意回退(commit bb821ab6)。回退原因是:助手头像在每条消息中都会渲染,强制验证会导致每次渲染都产生网络往返,而 Stale 问题只发生在管理员编辑头像 URL 后且直到下一次硬刷新为止。核心团队认为这种成本收益权衡不可接受,因此移除了该修复。

环境排查

  • 确认 Open WebUI 版本(v0.10.2 或 main 分支)
  • 确认浏览器类型和版本(Chrome、Firefox)
  • 确认是否使用了反向代理(如 Caddy)并检查该代理是否对 302 响应进行了缓存
  • 检查后端 ENV 变量 ENABLE_PROFILE_IMAGE_URL_FORWARDING 是否启用

解决步骤

  1. 后端修复(可优先尝试):get_model_profile_image() 中所有 302 响应中添加 Cache-Control: no-store 头。具体方式如下:

    • 对于使用 Response 的直接 302:headers={"Location": profile_image_url, "Cache-Control": "no-store"}
    • 对于 RedirectResponseheaders={"Cache-Control": "no-store"}

    Issue 作者建议使用 no-store 而非 no-cache,因为重定向目标可能随时改变(管理员更新),且没有可用的重新验证语义——需要浏览器每次重新询问后端。

  2. 前端修复(防御性编程):在头像 URL 中添加基于 model.info.updated_at 的缓存破坏参数 &v=${model?.info?.updated_at ?? ""}。修改文件 src/lib/components/chat/Messages/ResponseMessage.svelte 中的 src 构造。

  3. 注意:仅修复后端或仅修复前端任一方案均可解决问题。同时实施两者为“双重保险”。

验证方法

  1. 完成修复后,通过 API 将模型的 profile_image_url 更新为另一个图片 URL(例如从 https://example.com/a.png 改为 https://example.com/b.png)。
  2. 在同一浏览器标签页中发送一条新消息给该模型(不做硬刷新)。
  3. 检查助手头像是否立即更新为新图片。若更新,则问题解决。
  4. 打开 DevTools → Network,确认针对 /api/v1/models/model/profile/image?id=... 的请求未被从磁盘缓存提供服务,且响应头中包含 Cache-Control: no-store(后端修复)或 URL 中携带了 &v=... 参数(前端修复)。

参考来源

open-webui/open-webui #26858

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 15275

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注