为什么Cloudflare默认跳转会丢失UTM参数?
很多站长在Cloudflare开启了"始终使用HTTPS"或者配置了页面规则做HTTP跳转HTTPS,结果发现Google Analytics里的UTM参数全丢了,流量来源全部变成了direct。这个问题太常见了,原因也很简单——Cloudflare的"始终使用HTTPS"功能在做302跳转时,不会自动保留查询字符串。
具体来说,当用户访问 http://example.com?utm_source=wechat 时,Cloudflare的默认跳转可能只把用户送到 https://example.com,后面的 ?utm_source=wechat 就没了。你的流量归因数据就这么消失了。
方案一:Cloudflare Workers保留查询参数(推荐)
这是最灵活、最可靠的方案。用Workers拦截请求,手动拼接完整URL再做301跳转,查询参数一个都不会丢。
核心代码
export default {
async fetch(request) {
const url = new URL(request.url);
// 只处理HTTP请求,HTTPS直接放行
if (url.protocol === 'http:') {
const destinationURL = `https://${url.hostname}${url.pathname}${url.search}`;
return Response.redirect(destinationURL, 301);
}
return fetch(request);
}
};
关键就在 url.search 这一段——它包含了原始URL的所有查询参数,包括UTM参数。这样跳转后的地址就是 https://example.com?utm_source=wechat,参数完整保留。
部署步骤
- 登录Cloudflare Dashboard,进入Workers & Pages
- 点击"创建应用程序",选择"创建Worker"
- 把上面的代码粘贴到编辑器中
- 点击"保存并部署"
- 回到你的域名设置,添加一条路由:
yourdomain.com/*指向这个Worker
注意:如果你同时开了"始终使用HTTPS",建议关掉,让Worker来处理跳转逻辑,避免两个跳转规则冲突。
方案二:Cloudflare Transform Rules保留参数
如果你不想写代码,Cloudflare的Transform Rules也能实现类似效果。这个方案适合简单场景。
配置方法
- 进入Cloudflare Dashboard → Rules → Transform Rules
- 点击"Modify URL"
- 设置条件:当
URI Scheme等于HTTP时 - 操作选择"重写URL",类型选"301永久重定向"
- 目标URL填:
https://yourdomain.com${uri}
这里的 ${uri} 会自动包含路径和查询字符串,相当于Nginx里的 $request_uri。
局限性:Transform Rules的变量替换功能在某些套餐下可能不可用,免费套餐支持的规则数量也有限。如果你的跳转逻辑比较复杂,还是用Workers更灵活。
方案三:页面规则配合查询字符串保留
Cloudflare的页面规则(Page Rules)也可以做301跳转,但需要特别注意查询字符串的处理。
配置要点
- 创建页面规则,匹配URL填
http://yourdomain.com/* - 设置"Forwarding URL",类型选"301 - Permanent"
- 目标URL填
https://yourdomain.com/$1
但这里有个坑:页面规则的 $1 只捕获路径,不包含查询字符串。所以这个方案并不适合保留UTM参数,除非你把匹配模式改成更精细的正则。
实际操作中,页面规则更适合做整站跳转,不太适合需要保留参数的场景。
Workers方案进阶:处理特殊参数场景
场景一:跳转时追加额外参数
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.protocol === 'http:') {
url.protocol = 'https:';
url.searchParams.set('redirected', '1');
return Response.redirect(url.toString(), 301);
}
return fetch(request);
}
};
用 URLSearchParams API追加参数,比手动拼接字符串安全得多,不用担心重复的问号或者编码问题。
场景二:只保留UTM参数,过滤其他参数
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.protocol === 'http:') {
const newUrl = new URL(`https://${url.hostname}${url.pathname}`);
for (const [key, value] of url.searchParams) {
if (key.startsWith('utm_')) {
newUrl.searchParams.set(key, value);
}
}
return Response.redirect(newUrl.toString(), 301);
}
return fetch(request);
}
};
这个写法只保留 utm_ 开头的参数,其他参数全部丢弃。适合你想要"清洁URL"同时又不想丢失流量归因数据的场景。
场景三:多域名跳转保留完整参数
export default {
async fetch(request) {
const url = new URL(request.url);
const domainMap = {
'old-domain.com': 'new-domain.com',
'www.old-domain.com': 'new-domain.com',
};
const target = domainMap[url.hostname];
if (target) {
const destinationURL = `https://${target}${url.pathname}${url.search}`;
return Response.redirect(destinationURL, 301);
}
return fetch(request);
}
};
做域名迁移的时候,这个脚本能把旧域名的所有请求(连同查询参数)都跳转到新域名。
验证跳转是否保留了UTM参数
部署完成后,用curl验证一下:
curl -v "http://yourdomain.com/?utm_source=test&utm_medium=cpc" 2>&1 | grep Location
如果返回的Location头里包含完整的 ?utm_source=test&utm_medium=cpc,说明参数保留了。如果只有 https://yourdomain.com/,那就是参数丢了,需要回去检查配置。
也可以直接在浏览器里测试:地址栏输入带UTM参数的HTTP地址,看跳转后地址栏里参数还在不在。
Workers vs 其他方案对比
- Workers:最灵活,能处理各种复杂场景,免费套餐每天10万次请求足够小站使用
- Transform Rules:零代码,但免费套餐只有10条规则,复杂跳转搞不定
- 页面规则:参数保留能力弱,而且Cloudflare已经逐步用Transform Rules替代页面规则
- "始终使用HTTPS":最省事,但参数可能丢失,不推荐用于有UTM追踪需求的站点
常见问题
Workers和"始终使用HTTPS"能同时开吗?
可以,但不建议。两个跳转逻辑可能冲突,导致双重跳转或者参数丢失。建议关掉"始终使用HTTPS",让Worker统一处理。
Workers会影响网站性能吗?
Workers在Cloudflare的边缘节点执行,跳转响应通常在50ms以内,对用户体验几乎没有影响。而且301跳转浏览器会缓存,后续访问直接走HTTPS,不需要再经过Worker。
免费套餐够用吗?
Cloudflare Workers免费套餐每天10万次请求,对于日PV低于10万的站点完全够用。如果超了,5美元/月的付费套餐提供1000万次请求,性价比很高。
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论