页面接口换图后不刷新,刷新页面后才看得到新图 前阵子做后台的一个小需求:配置列表每行几张图片,点「编辑」传张新图、保存,列表就地刷新。能力看着平平无奇,结果测的时候发现传完图、保存成功,列表信息也重新请求过了,可那张图还是原来的图,有时候干脆裂了。但我只要刷新页面,新图立马就出来。 数据我翻来覆去看了,接口返回的 URL 一个不差;把那个 URL 单独贴到浏览器地址栏打开,图也好好的。但是列表还是原来的图。 先别急着看代码,有没有可能是资源缓存了? 这种「局部更新不行、整页刷新就行」的毛病,我第一反应是缓存。因为这两种刷新对图片资源根本不是一回事: AJAX 局部更新,Vue 重渲染, 的 src 变了才会去重新请求;没变的话,浏览器直接拿内存里那份,连请求都不发。而 F5 会把页面上的资源整个重新请求一遍。 顺着「是不是缓存」这条线,我打开 DevTools 的 Network 面板,保存之后盯着那张图的请求看——好家伙, 压根没发新请求 ,那一行写着 (from memory cache) 。到这儿基本实锤了:浏览器用的是缓存。 那为什么会命中缓存?再去对比保存前后的图片 URL,问题的根子就浮出来了—— 后端是把新图覆盖上传到了同一个固定地址 ,比如永远叫 tab1.png 。前后 URL 一模一样。 这么一看整件事就顺了: 页面第一次加载,浏览器请求 tab1.png ,把旧图缓存下来。 我换图保存,后端把存储上的 tab1.png 覆盖成了新图,可地址没变。 前端重新拉列表,
的 src 还是 tab1.png ,跟之前完全一样。 浏览器一看这地址有缓存,直接用旧的,不重新请求。 我按 F5,资源全部重新拉,新图才露面。 顺手也可以用 curl 看一眼这张图的响应头,确认它确实是可被缓存的: curl -sI "https://xxx-oss.example.com/static/icons/tab1.png" 返回里如果带着 Cache-Control: max-age=... 、 Last-Modified 、 ETag 这类,就说明浏览器有充分理由把它缓存住、下次不再问服务器。配合 Network 面板里那句 (from memory cache) ,缓存这个结论就很稳了。 解法:让 URL 变一下 问题既然是「URL 没变、命中旧缓存」,思路就很直接:给图片地址拼一个会变的参数,骗浏览器这是张新图。 https://xxx-oss.example.com/static/icons/tab1.png? t = 1720857600000 对象存储(OSS / COS 之类)不认识 ?t= 这个参数,会忽略它、照样把图返回来;但浏览器看到 query 变了,就当成一个新 URL 去重新请求,自然就绕开了旧缓存。 具体到 Vue 2 + Element UI,就是加一个会变的时间戳,拉列表时刷新它,再用一个方法给图片地址拼上去: data () { return { list: [], imgTs: Date.now(), // 图片缓存戳 } }, methods: { getList() { this .loading = true getList( this .query).then(res => { if (res.success) { this .list = res.value this .imgTs = Date.now() // 每次拿到数据就换个戳 } this .loading = false }) }, imgSrc(url) { if (!url) return url return url + (url.includes( '?' ) ? '&' : '?' ) + 't=' + this .imgTs }, }, 模板里用 imgSrc() 包一层就行:
保存成功会走 getList() , imgTs 一变,图片 URL 就带上新的 ?t=... ,浏览器乖乖重新请求,不用再按 F5 了。 imgSrc 是在模板里当方法调的,每次重渲染都会跑一遍;但只有 imgTs 真的变了、返回的 URL 才会变。所以效果就是「拉列表的时候强制重取,平时不折腾」。 几个可以多想一步的地方 为什么不干脆让后端换个随机文件名? 那样 URL 每次都变,前端确实不用加戳。但覆盖同名也有它的道理——地址稳定、不会攒一堆历史垃圾文件,挺常见的做法。所以前端这个戳更像是个通用兜底,不指望后端改约定,成本也低。 每次拉列表都重新下图,会不会浪费? 会。加了会变的 ?t= 之后,这些图就不走缓存了,每次刷列表都重新下。对这种图少、图小的配置页无所谓;要是大列表大图,就别每次都换戳,改成只在保存成功之后才换: save( data ).then(res => { if (res.success) { this .imgTs = Date.now() // 只在更新后强制重取,平时走缓存 this .getList() } }) 万一加了戳还是偶尔裂图? 那可能就不是缓存的锅,而是对象存储上传有延迟——保存接口在图还没完全写进存储时就返回了,前端立刻去请求,对象还不在。想区分很简单:保存后先别刷新,干等几秒,图会不会自己好?会自己好,就是上传延迟,得让后端「传完再返回」或者前端延后一点再拉列表;不会好,那才是缓存。 最后 这次卡壳,真正费时间的其实不是改代码,是「意识到该往缓存方向查」。后面再遇到这种莫名其妙的显示问题,我基本都会先手贱按个 F5——能好,那八成就是缓存或者资源加载层面的事,排查范围一下子就窄下来了。
页面接口换图后不刷新,刷新页面后才看得到新图
页面接口换图后不刷新,刷新页面后才看得到新图 前阵子做后台的一个小需求:配置列表每行几张图片,点「编辑」传张新图、保存,列表就地刷新。能力看着平平无奇,结果测的时候发现传完图、保存成功,列表信息也重新请求过了,可那张图还是原来的图,有时候干脆裂了。但我只要刷新页面,新图立马就出来。 数据我翻来覆去看了,接口返回的 URL 一个不差;把那个 URL 单独贴到浏览器地址栏打开,图也好好的。但是列表还是...

