如何利用 Cloudflare Worker 实现 Navidrome 的“白嫖版”全球加速。
Tip
我的第一次白嫖方案,大家都用什么方案进行cdn缓存媒体流的呢?
// 前言: 给辛苦熬夜的楼主加个“鸡腿🍗点个赞👍”,方便我们在 F12 调试时相遇
let newHeaders = new Headers(response.headers);
newHeaders.set('X-Navidrome-Cache', 'Worker-Active');
第三天深夜被Gemini折磨PUA我开Plus 
我是小白,所以求大佬狠狠指教. 
🚀 Navidrome 媒体流 Worker 加速部署终极指南
一、 为什么必须使用 Worker 方案?
在 Cloudflare 的常规设置中,“忽略查询字符串(Ignore Query String)” 是一个能让 CDN 忽略 URL 中动态参数(如 Token)的功能。
- 付费门槛:在免费版 Cloudflare 中,这个功能极难配置生效,通常需要 $20/月 的 Pro 计划才能精准控制。
- Worker 的优势:通过代码手动剥离动态参数。它相当于让你在 免费版 上实现了 企业级 的缓存定制逻辑。
二、 深度拆解:媒体链接的“众生相”
以示例链接为例:
https://music.expler.com/rest/getTranscodeStream?u=ns&t=ec4d...&s=60a5...&mediaId=useen...&transcodeParams=eyJ...
我们将这个长链接拆解为以下逻辑,方便你理解 Worker 是如何“做手术”的:
| 组成部分 | 示例内容 | Worker 的处理逻辑 | 作用与意义 |
|---|---|---|---|
| 请求动作 | /rest/getTranscodeStream |
保留 | 识别这是“取歌”指令,触发 Worker 拦截逻辑。 |
| 动态令牌 | t=ec4d... / s=60a5... |
剔除 (Delete) | 每次登录/刷新都会变。剔除它是缓存命中的核心。 |
| 核心指纹 | mediaId=useen... |
锁定 (Key) | 歌曲的唯一身份证。Worker 强制以此作为搜索索引。 |
| 转码参数 | transcodeParams=eyJ... |
保留 | 决定是 FLAC 还是 MP3。保留它可防止音质混淆。 |
三、 Worker 部署代码
在 Cloudflare Worker 编辑器中,删除原有内容,粘贴以下代码:
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 只拦截包含 /rest/ 的请求(涵盖了图片和音频流)
if (url.pathname.includes('/rest/')) {
let newRequest = new Request(request);
// 1. 彻底移除干扰缓存的标头(免费版 CF 缓存的关键)
newRequest.headers.delete('Cookie');
newRequest.headers.delete('Authorization');
// 2. 重新构造缓存密钥 (Cache Key)
// 忽略动态 Token,只提取 mediaId (或 id) 和转码参数
const mid = url.searchParams.get('id') || url.searchParams.get('mediaId');
const tparams = url.searchParams.get('transcodeParams') || '';
// 构造一个纯净的内部 URL 用于缓存索引
const cacheKey = `${url.origin}${url.pathname}?id=${mid}&tp=${tparams}`;
// 3. 强制云端缓存
const response = await fetch(newRequest, {
cf: {
cacheEverything: true, // 强制缓存所有内容,无视后缀名
cacheTtl: 31536000, // 边缘节点缓存建议 1 年
cacheKey: cacheKey, // 使用我们自定义的纯净指纹
cacheTtlByStatus: { "200-299": 31536000, "404": 1, "500-599": 0 }
}
});
// 4. 给响应头加个“暗号”,方便我们在 F12 调试
let newHeaders = new Headers(response.headers);
newHeaders.set('X-Navidrome-Cache', 'Worker-Active');
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
});
}
// 非 /rest/ 请求(如网页登录页)直接透传,不消耗额外逻辑
return fetch(request);
}
};
四、 部署过程(处处有回应)
- 创建 Worker:在 Cloudflare 控制台左侧点击 "Workers 和 Pages",创建一个新的 Worker,命名为
navidrome-optimizer。 - 部署代码:点击 "编辑代码",粘贴上方代码并点击右上方 "部署"。
- 设置路由(核心):
- 进入该 Worker 的 "设置" -> "域和路由"。
- 点击 "添加路由"。
- 路由填写:
music.expler.com/rest/*(最后的*代表匹配所有子路径)。 - 区域选择:
expler.com。
- 失败模式设置:
- 在路由页面,将失败模式改为 「失败时自动打开(继续)」。
- 回应:这能保证万一 Worker 每天 10 万次免费额度用完,你的音乐依然能听(只是变慢了),不会报 500 错误。
五、 进阶:SaaS 加速与能力扩展
1. SaaS 加速(优选 IP)
- 效果:SaaS 加速优化的是“网络链路”(修路),Worker 优化的是“数据获取”(仓库)。
- 结论:两者叠加效果翻倍。SaaS 让请求飞快到达 CF 节点,Worker 让请求在节点直接命中,不再回传家宽。
2. 能力扩展
这个 Worker 还可以根据你的需求继续进化:
- 图片即时压缩:检测到移动端访问时,自动将
getCoverArt请求的图片在边缘节点压缩后再发送。 - 防盗链:可以设置
Referer校验,只允许你自己的二级域名或特定 App 访问音乐流。 - 地区限制:利用
request.cf.country属性,只允许你指定的国家/地区访问。
六、 部署成功的标志
打开 music.expler.com 播放音乐,按下 F12:
- Headers 中必须出现
X-Navidrome-Cache: Worker-Active。
- Cf-Cache-Status:
- 第一次播放:
MISS(正在搬运)。 - 第二次或刷新后播放:
HIT(家宽上行 0 消耗,秒开)。
- 第一次播放: