模板里写死 `__STATIC__` 之后,我的移动端和PC端资源在CDN上"打架"了两天

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
站长杂谈 73 浏览 0 回复

上周给老项目做响应式改造,踩了个特别隐蔽的坑,记录一下。

项目用的是ThinkPHP6,模板继承结构大概是这样:一个基础 `layout.html`,里面放了通用的 head,然后PC端和移动端各自继承。我图省事,在 layout 里直接写了 ``,想着子模板覆盖 `block` 就行,静态资源反正大家都用同一套。

问题出在CDN刷新策略上。

我们的静态资源是推到阿里云OSS然后挂CDN的,为了区分渠道,PC端和移动端其实是两个不同的子域名:pc.cdn.xxx.com 和 m.cdn.xxx.com,但指向的是同一个OSS bucket,只是CDN回源路径加了前缀区分。我在 `config/view.php` 里配了 `tpl_replace_string`,把 `__STATIC__` 替换成 `https://pc.cdn.xxx.com/static`,PC端跑得稳稳当当。

移动端模板继承同一份 layout,渲染出来的 `common.css` 自然也是 pc.cdn 开头的。当时脑子一抽,觉得"反正CSS一样,跨域引用也没事",就没管。

结果第二天测试反馈:移动端偶发样式错乱,刷新又好了。我抓包一看,CDN节点有时候返回的是PC版的压缩CSS(我们把响应式拆成了两个文件,只是名字一样,放在不同目录),有时候又是正常的。排查了半天OSS,最后才反应过来:两个子域名共享CDN节点缓存键,URL路径一样的时候,节点根本分不清这是PC还是移动请求,直接命中了对方的缓存。

更坑的是,我在移动端模板里后来加了一段 `__STATIC__/css/mobile.css` 试图覆盖,但因为模板继承的顺序,`common.css` 已经以PC域名加载了,浏览器的CORS预检在某些环境下还出了警告。

最后的解法其实不复杂,但绕了一大圈:

1. 把 `__STATIC__` 从 layout 里清掉,每个端各自在 `block` 里完整写自己的资源路径;

2. 给CDN配了 `Vary: User-Agent`,但老项目CDN版本不支持这么细的规则,只能放弃;

3. 最实在的改动:移动端单独配了一个 `__M_STATIC__` 替换规则,彻底断开和PC端的路径耦合。

这事给我提了个醒:模板继承里的资源路径,"复用"和"隔离"的边界要比业务逻辑更敏感。`__STATIC__` 这种全局替换看着方便,一旦多端、多环境、多CDN策略混起来,就是颗延时雷。现在我的习惯是,基础 layout 只留框架结构,任何带域名的资源引用都下沉到具体端模板里,宁可多写几行,也不让解析边界模糊掉。

另外个小发现:ThinkPHP的 `tpl_replace_string` 是在模板编译时做的字符串替换,不是运行时,所以改完配置记得清 `runtime/view` 的编译缓存,别问我怎么知道的。

评论0
回复 · 0
还没有回复
微信客服 微信客服