站点图标 高效码农

Cloudflare Workers救星!Google Ads暴跌90%?揭CDN吃广告收入的致命陷阱与完美修复方案

Cloudflare Workers 优化 Google Ads 收入完全指南:解决 CDN 代理导致广告收入骤降的问题

为什么接入 Cloudflare 后 Google Ads 收入会大幅下降?

很多站长在将网站接入 Cloudflare CDN 后,都会遇到一个令人困惑的问题:Google AdSense 的展示次数和千次展示收入(CPM)突然大幅下降。这不是偶然现象,而是 Cloudflare 的工作机制导致的必然结果。

问题的根本原因

当你的网站使用 Cloudflare 作为 CDN 和反向代理时,所有访问者的请求都会先经过 Cloudflare 的服务器,然后再转发到你的源服务器。这个过程中会出现以下问题:

IP 地址被替换:访问者的真实 IP 地址被 Cloudflare 的 IP 地址替换。比如一个来自中国北京的访客,在经过 Cloudflare 的阿姆斯特丹节点后,你的服务器看到的 IP 地址变成了荷兰的 IP。

地理位置定向失效:Google Ads 依赖准确的地理位置信息来投放广告。当广告主设置只向中国用户展示广告时,系统却认为这是来自荷兰的访问,导致广告无法正确展示。

用户画像被破坏:Cloudflare 的缓存和代理会干扰 Google Ads 的用户追踪机制,导致广告个性化投放失败,只能展示低价值的通用广告。

实际影响数据:某网站接入 Cloudflare 前后的对比数据显示,页面浏览量 1245 次,但广告展示次数仅 285 次,展示率只有 23%。CPM 从正常的 0.50-2.00 美元骤降至 0.05 美元,点击率也从正常的 0.5-2% 降至 0.08%。

Cloudflare Workers 是什么?如何解决这个问题?

Cloudflare Workers 是一个在 Cloudflare 边缘网络上运行的无服务器计算平台。它允许你在请求到达服务器之前,在 Cloudflare 的边缘节点上执行 JavaScript 代码,修改请求和响应。

Workers 的核心功能是拦截经过 Cloudflare 的每一个 HTTP 请求,你可以:

  • 读取和修改请求头信息
  • 添加自定义的 HTTP 头
  • 控制缓存策略
  • 转发真实的访客 IP 地址
  • 根据不同条件执行不同的逻辑

通过 Workers,我们可以在请求转发到源服务器之前,将访客的真实 IP 地址和地理位置信息添加到 HTTP 头中,让你的网站和 Google Ads 能够获取准确的访客信息。

完整解决方案:部署 Cloudflare Workers

第一步:创建 Worker

  1. 登录 Cloudflare Dashboard(https://dash.cloudflare.com)
  2. 在左侧菜单找到”Workers & Pages”
  3. 点击”Create application”或”Create Worker”按钮
  4. 给 Worker 命名,例如”google-ads-optimizer”
  5. 点击”Deploy”部署默认代码

第二步:编写 Worker 代码

点击”Edit Code”进入代码编辑器,删除所有默认代码,粘贴以下完整代码:

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  const realIP = request.headers.get('CF-Connecting-IP') || 'unknown'
  const country = request.headers.get('CF-IPCountry') || 'unknown'
  
  // 广告相关关键词
  const adKeywords = [
    'adsbygoogle',
    'googlesyndication',
    'doubleclick',
    'pagead',
    'googletagservices',
    'googletagmanager',
    'google-analytics'
  ]
  
  // WordPress 后台和动态路径列表
  const wpAdminPaths = [
    '/wp-admin',
    '/wp-login.php',
    '/wp-json/',
    '/xmlrpc.php',
    '/wp-cron.php',
    '/wp-comments-post.php',
    '?preview=',
    '/checkout/',
    '/cart/',
    '/my-account/'
  ]
  
  // 检查各种请求类型
  const isAd = adKeywords.some(keyword => 
    url.href.toLowerCase().includes(keyword)
  )
  
  const isTxt = url.pathname.toLowerCase().endsWith('.txt')
  
  const isWpAdmin = wpAdminPaths.some(path => 
    url.pathname.includes(path) || url.search.includes(path)
  )
  
  const isPostRequest = request.method === 'POST'
  
  const cookies = request.headers.get('Cookie') || ''
  const isLoggedIn = cookies.includes('wordpress_logged_in') || 
                     cookies.includes('wp-settings-')
  
  // 需要绕过缓存的请求
  const noCache = isAd || isTxt || isWpAdmin || isPostRequest || isLoggedIn
  
  // 添加真实IP到请求头
  const headers = new Headers(request.headers)
  headers.set('X-Real-IP', realIP)
  headers.set('X-Forwarded-For', realIP)
  headers.set('X-Country', country)
  headers.set('X-Forwarded-Proto', 'https')
  headers.set('X-Original-IP', realIP)
  
  // 添加请求类型标记
  if (isAd) headers.set('X-Ad-Request', 'true')
  if (isTxt) headers.set('X-Txt-File', 'true')
  if (isWpAdmin) headers.set('X-WP-Admin', 'true')
  if (isPostRequest) headers.set('X-Post-Request', 'true')
  if (isLoggedIn) headers.set('X-Logged-In', 'true')
  
  const modifiedRequest = new Request(request, { headers })
  
  // 获取响应
  const response = await fetch(modifiedRequest, {
    cf: noCache ? { 
      cacheTtl: 0, 
      cacheEverything: false 
    } : { 
      cacheTtl: 3600,
      cacheEverything: true 
    }
  })
  
  // 创建新响应并添加标记
  const newResponse = new Response(response.body, response)
  newResponse.headers.set('X-Worker-Status', 'active')
  newResponse.headers.set('X-Worker-Version', '1.3')
  newResponse.headers.set('X-Visitor-IP', realIP)
  newResponse.headers.set('X-Visitor-Country', country)
  newResponse.headers.set('X-Ad-Optimized', isAd ? 'yes' : 'no')
  
  // 强制不缓存
  if (noCache) {
    newResponse.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate, private')
    newResponse.headers.set('Pragma', 'no-cache')
    newResponse.headers.set('Expires', '0')
    newResponse.headers.set('X-Cache-Bypass', 'true')
    
    if (isWpAdmin) newResponse.headers.set('X-No-Cache-Reason', 'wp-admin')
    else if (isPostRequest) newResponse.headers.set('X-No-Cache-Reason', 'post-request')
    else if (isLoggedIn) newResponse.headers.set('X-No-Cache-Reason', 'logged-in')
    else if (isTxt) newResponse.headers.set('X-No-Cache-Reason', 'txt-file')
    else if (isAd) newResponse.headers.set('X-No-Cache-Reason', 'ad-request')
  }
  
  return newResponse
}

点击右上角”Save and Deploy”保存并部署。

第三步:配置 Routes 路由

Worker 部署后需要绑定到你的域名才能生效:

  1. 在 Worker 页面点击”Triggers”标签
  2. 找到”Routes”部分,点击”Add route”
  3. 添加第一条路由:
    • Route:yourdomain.com/*(替换为你的域名)
    • Zone:选择你的域名
  4. 添加第二条路由:
    • Route:www.yourdomain.com/*
    • Zone:选择你的域名
  5. 确保两条路由的状态都显示为”Active”

第四步:配置 WordPress 接收真实 IP

在 WordPress 网站的 wp-config.php 文件中,在 require_once(ABSPATH . 'wp-settings.php'); 这一行之前添加以下代码:

/**
 * Cloudflare 真实 IP 恢复
 */
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
    $_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (isset($_SERVER['HTTP_X_REAL_IP'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $forwardedIPs = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = trim($forwardedIPs[0]);
}

if (isset($_SERVER['HTTP_CF_IPCOUNTRY'])) {
    define('VISITOR_COUNTRY', $_SERVER['HTTP_CF_IPCOUNTRY']);
}
if (isset($_SERVER['HTTP_X_COUNTRY'])) {
    define('VISITOR_COUNTRY_WORKER', $_SERVER['HTTP_X_COUNTRY']);
}

第五步:清除缓存

  1. 回到 Cloudflare Dashboard
  2. 选择你的域名
  3. 左侧菜单选择”Caching” → “Configuration”
  4. 点击”Purge Everything”按钮
  5. 确认清除所有缓存
  6. 等待 2-3 分钟让 Worker 在全球节点生效

如何验证 Worker 是否正常工作?

方法一:使用命令行测试

在终端或命令提示符中运行以下命令:

curl -sI https://www.yourdomain.com/ | grep -i "x-"

正常情况下应该看到以下响应头:

x-worker-status: active
x-visitor-ip: 你的真实IP地址
x-visitor-country: CN
x-real-ip: 你的真实IP地址
x-forwarded-for: 你的真实IP地址
x-ad-optimized: no

方法二:创建测试页面

在网站根目录创建 worker-test.php 文件,内容如下:

<?php
header('Content-Type: text/plain; charset=utf-8');

echo "=== Cloudflare Worker 状态检测 ===\n\n";

$checks = [
    'CF-Ray' => $_SERVER['HTTP_CF_RAY'] ?? null,
    'CF-Connecting-IP' => $_SERVER['HTTP_CF_CONNECTING_IP'] ?? null,
    'CF-IPCountry' => $_SERVER['HTTP_CF_IPCOUNTRY'] ?? null,
    'X-Real-IP' => $_SERVER['HTTP_X_REAL_IP'] ?? null,
    'X-Forwarded-For' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null,
    'X-Country' => $_SERVER['HTTP_X_COUNTRY'] ?? null,
    'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? null,
];

foreach ($checks as $key => $value) {
    $status = $value ? '✅' : '❌';
    echo "$status $key: " . ($value ?: '未检测到') . "\n";
}

echo "\n=== 判断结果 ===\n";
if ($checks['CF-Ray'] && $checks['X-Real-IP']) {
    echo "🎉 Worker 完美运行!真实IP已传递!\n";
} elseif ($checks['CF-Ray']) {
    echo "⚠️ 流量经过 Cloudflare,但 Worker 未添加自定义头\n";
} else {
    echo "❌ 流量未经过 Cloudflare\n";
}
?>

访问 https://www.yourdomain.com/worker-test.php,如果显示”Worker 完美运行”,说明配置成功。

方法三:检查浏览器开发者工具

  1. 打开你的网站
  2. 按 F12 打开开发者工具
  3. 切换到”Network”标签
  4. 刷新页面(Ctrl+F5)
  5. 点击第一个请求(通常是网站首页)
  6. 查看”Response Headers”部分

应该能看到 x-worker-status: activex-visitor-ip 等自定义响应头。

Worker 代码的核心功能解析

真实 IP 传递机制

Worker 通过读取 Cloudflare 提供的 CF-Connecting-IP 头来获取访客的真实 IP 地址,然后将这个信息添加到多个标准的 HTTP 头中:

  • X-Real-IP:自定义头,直接包含真实 IP
  • X-Forwarded-For:标准的代理转发头
  • X-Original-IP:备份的真实 IP 信息
  • X-Country:访客所在国家代码

这种多重保障确保 WordPress、Google Ads 和其他服务都能准确获取访客信息。

智能缓存控制

Worker 会根据请求类型自动调整缓存策略:

不缓存的内容

  • Google Ads 相关脚本和请求
  • WordPress 后台页面(/wp-admin、/wp-login.php)
  • REST API 接口(/wp-json/)
  • POST 请求(表单提交、AJAX)
  • 已登录用户的请求
  • .txt 等文本文件

正常缓存的内容

  • 静态资源(CSS、JavaScript、图片)
  • 未登录用户访问的前台页面
  • HTML 页面

这种策略既保证了广告和后台的实时性,又充分利用了 CDN 的加速优势。

请求类型识别

Worker 通过以下方式识别不同类型的请求:

广告请求识别:检查 URL 中是否包含 adsbygooglegooglesyndicationdoubleclick 等关键词。

后台请求识别:检查路径是否包含 /wp-admin/wp-login.php 等 WordPress 后台地址。

用户登录状态:检查 Cookie 中是否包含 wordpress_logged_in 标识。

请求方法:识别 GET、POST 等不同的 HTTP 方法。

预期效果和改善时间表

立即生效的改变

  • Worker 部署后 2-3 分钟即可在全球边缘节点生效
  • 真实 IP 信息立即开始传递给源服务器
  • WordPress 后台和广告请求不再被缓存

24-48 小时后的改善

Google Ads 系统需要一定时间来重新识别和分析你的流量质量。通常在 24-48 小时后会看到明显改善:

展示次数:从原来的 285 次提升到 500-800 次,增长约 100-200%。原因是 Google 现在能准确识别访客位置,投放更多针对性广告。

千次展示收入(CPM):从 0.05 美元提升到 0.50-2.00 美元,增长 10-40 倍。高价值地区的广告主能够正常出价竞争。

点击率(CTR):从 0.08% 提升到 0.3-1.0%,增长 4-12 倍。广告更加相关,用户更愿意点击。

展示率:从 23% 提升到 60-80%。更多的页面浏览能够成功触发广告展示。

长期稳定效果

一周后,Google Ads 完全适应新的流量特征,收入应该恢复到接入 Cloudflare 之前的水平,甚至更好。因为你既享受了 Cloudflare 的速度优势,又保持了广告的精准投放能力。

常见问题排查

问题一:Worker 部署后没有效果

检查 Routes 配置:确保在 Worker 的 Triggers → Routes 中添加了正确的路由规则,格式为 yourdomain.com/*www.yourdomain.com/*,状态必须是 Active。

检查 DNS 代理状态:在 Cloudflare 的 DNS → Records 页面,确保 A 记录或 CNAME 记录的云朵图标是橙色的(Proxied),而不是灰色的(DNS only)。灰色云朵表示流量不经过 Cloudflare,Worker 无法工作。

清除缓存:部署 Worker 后必须清除 Cloudflare 的缓存,否则会继续返回旧的缓存内容。

问题二:看不到 X-Real-IP 响应头

确认 Worker 代码完整:检查代码中是否包含 headers.set('X-Real-IP', realIP) 这一行,确保没有复制粘贴错误。

等待生效时间:Worker 的全球部署需要 2-3 分钟,不要立即测试。

使用无痕模式测试:浏览器缓存可能影响测试结果,使用无痕模式或清除浏览器缓存后再测试。

问题三:广告还是展示不正常

检查 WordPress 配置:确认 wp-config.php 中的 IP 恢复代码已正确添加,位置必须在 require_once 之前。

查看 AdSense 后台:登录 Google AdSense 后台,查看是否有”无效流量”或其他警告信息。

检查流量来源:使用 Google Analytics 或其他工具查看流量的地理位置分布是否正常,确认访客国家代码正确。

给予足够时间:Google Ads 需要 24-48 小时来重新评估流量质量,不要期待立即改善。

问题四:网站速度变慢

检查缓存配置:确认 Worker 代码中 cacheTtl 参数设置正确,普通页面应该使用 3600(1小时)缓存。

优化 Worker 代码:如果 Worker 逻辑太复杂,可能影响响应速度。使用简化版本的 Worker 代码,只保留核心功能。

监控 Worker 性能:在 Cloudflare Dashboard 的 Workers & Pages → 你的 Worker → Metrics 中查看执行时间和成功率。

Worker 的额外优势

保护 WordPress 后台安全

Worker 代码中已经包含了对 WordPress 后台路径的特殊处理,这些页面不会被缓存,确保管理员总是看到最新内容。同时,POST 请求和已登录用户的请求也不会被缓存,避免敏感信息泄露。

支持电商网站功能

如果你的网站使用 WooCommerce 等电商插件,Worker 已经针对购物车(/cart/)、结账页面(/checkout/)、用户账户(/my-account/)等动态页面设置了不缓存策略,确保购物流程正常工作。

灵活的扩展性

Worker 代码采用模块化设计,你可以根据需要轻松添加更多功能:

  • 添加更多不缓存的文件类型(.log、.xml、.json 等)
  • 添加更多需要保护的路径
  • 根据访客国家或 IP 执行不同的逻辑
  • 添加自定义的安全规则

成本效益

Cloudflare Workers 的免费计划每天提供 100,000 次请求额度,对于中小型网站完全够用。超出后的付费标准是每百万次请求 0.50 美元,成本非常低廉。

技术原理深入理解

Cloudflare 边缘网络架构

Cloudflare 在全球有超过 300 个数据中心,组成了一个庞大的边缘网络。当用户访问你的网站时,请求会被路由到最近的 Cloudflare 节点,而不是直接连接到你的源服务器。

Workers 运行在这些边缘节点上,在请求到达源服务器之前就完成了处理。这种架构的优势是:

低延迟:代码在距离用户最近的节点执行,响应速度快。

高可用:即使源服务器宕机,Worker 仍然可以返回缓存内容或错误页面。

减轻服务器负担:很多请求在边缘节点就被处理了,减少了源服务器的压力。

HTTP 头信息的作用

HTTP 头是 HTTP 协议的重要组成部分,包含了请求和响应的元数据。常见的请求头包括:

  • User-Agent:客户端的浏览器和操作系统信息
  • Cookie:客户端存储的会话信息
  • Referer:请求来源页面的 URL
  • Accept-Language:客户端接受的语言

Worker 通过添加自定义的 HTTP 头来传递额外信息,这些头信息对用户不可见,但服务器端的应用可以读取和使用。

Google Ads 的工作机制

Google Ads 依赖多种信号来决定展示什么广告:

地理位置:广告主可以设置广告只向特定国家、地区甚至城市的用户展示。

用户兴趣:通过分析用户的浏览历史和行为,Google 建立了详细的兴趣画像。

上下文相关性:广告内容会根据网页内容自动匹配。

竞价系统:多个广告主同时竞价,出价最高且质量得分最好的广告获胜。

当 Cloudflare 替换了真实 IP 后,地理位置信息错误,用户画像无法建立,导致广告主无法正确定向,竞价失败,最终只能展示低价值的通用广告。

实施建议和最佳实践

部署前的准备工作

备份现有配置:在修改任何配置前,先备份 wp-config.php 和其他关键文件。

选择合适的时间:建议在网站流量较低的时段(如凌晨)进行部署,减少对用户的影响。

准备测试工具:准备好测试页面和命令行工具,确保能够快速验证配置是否成功。

部署后的监控

持续观察 AdSense 数据:每天查看 AdSense 后台的展示次数、CPM、CTR 等关键指标,记录变化趋势。

监控网站性能:使用 Google PageSpeed Insights、GTmetrix 等工具监控网站加载速度,确保 Worker 没有影响性能。

检查错误日志:定期查看 Cloudflare 的 Worker 日志和 WordPress 的错误日志,及时发现问题。

优化建议

合理设置缓存时间:根据内容更新频率调整 cacheTtl 参数。经常更新的内容使用较短的缓存时间(如 1800 秒),静态内容可以使用更长的缓存时间(如 86400 秒)。

使用 Page Rules 配合:Cloudflare 的 Page Rules 可以为特定页面设置更精细的缓存策略,与 Worker 配合使用效果更好。

定期更新代码:随着 WordPress 和插件的更新,可能需要添加新的不缓存路径。定期检查并更新 Worker 代码中的路径列表。

总结

接入 Cloudflare CDN 后 Google Ads 收入骤降是一个常见但可以完美解决的问题。通过部署 Cloudflare Workers,我们可以在享受 CDN 加速优势的同时,保持广告系统对访客信息的准确识别。

Worker 的核心作用是传递真实的 IP 地址和地理位置信息,同时针对广告请求、WordPress 后台等特殊内容实施差异化的缓存策略。整个部署过程只需要 15-20 分钟,不需要修改网站核心代码,风险很低。

部署完成后,通常在 24-48 小时内就能看到明显的改善效果。展示次数、CPM 和点击率都会显著提升,网站的广告收入能够恢复到接入 CDN 之前的水平,甚至更好。

这个解决方案不仅适用于 Google AdSense,对于其他依赖准确地理位置信息的广告联盟、统计分析工具、安全防护系统等,都同样有效。它是一个值得所有使用 Cloudflare 的网站实施的优化方案。

退出移动版