WooCommerce geolocation_ajax 导致单品页 3 次跳转的排查与修复 (TTFB 2.5s→0.17s)

·0 次浏览
  • 作者
    帖子
  • weixiaoduo@weixiaoduo
    楼主

    问题

    WooCommerce 商城单品页 TTFB 高达 2.5 秒,但 WP Rocket 页面缓存已开启且首页缓存正常 (0.18s) 。

    用 curl 逐步追踪发现,单品页经历了 3 次跳转才到达最终缓存页面:

    /item/flarum/     →301→  /item/flarum              (0.78s, WordPress 去尾斜杠)
    /item/flarum      →307→  /item/flarum/?v=160222...  (0.81s, WC geolocation 加 ?v= 并带尾斜杠)
    /item/flarum/?v=  →301→  /item/flarum?v=160222...   (0.75s, WordPress 又去尾斜杠)
    /item/flarum?v=   →200                              (0.18s, 缓存命中)
    

    最终页面其实已被 WP Rocket 缓存 (0.18s),但用户要经过 3 次服务端跳转 (~2.3s) 才能到达。

    原因分析

    根源是 WooCommerce 核心的 WC_Cache_Helper::geolocation_ajax_redirect() 方法 (class-wc-cache-helper.php) 。

    当 woocommerce_default_customer_address 设为 geolocation_ajax 时,WooCommerce 会在每个非购物车/结算页面做 307 跳转,在 URL 上附加 ?v= 地理位置哈希参数,用于缓存区分不同地区的用户。

    问题出在跳转 URL 的构建:

    $redirect_url = trailingslashit( home_url( $wp->request ) );
    

    trailingslashit() 强制加尾斜杠,但如果 WordPress 的固定链接结构不含尾斜杠 (如 /%category%/%postname%),WordPress 会再做一次 301 去掉斜杠。这就造成了:

    1. WordPress 301 去尾斜杠
    2. WooCommerce 307 加 ?v= 并带回尾斜杠
    3. WordPress 301 再去尾斜杠
    4. 最终命中缓存

    每次跳转都是一次完整的服务端请求 (~0.7-0.8s),三次就是 ~2.3s 的纯浪费。

    解决方案

    对于数字商品商城 (不需要按地理位置显示不同价格/税率),直接禁用 geolocation_ajax:

    wp option update woocommerce_default_customer_address base_address --url=mall.weixiaoduo.com
    

    将默认客户地址从 geolocation_ajax 改为 base_address(使用商店基础地址) 。

    修改后清除页面缓存,让 WP Rocket 重新生成不含 ?v= 参数的缓存文件。

    修复效果

    指标 修复前 修复后
    单品页 TTFB(首次) ~2.5s(3 次跳转) ~1.2s(直接渲染)
    单品页 TTFB(缓存) ~2.5s(跳转不缓存) 0.17s(直接命中)
    307 跳转 每次访问都触发 完全消除
    首页 TTFB 0.18s(不受影响) 0.17s(不变)

    适用场景

    • 数字商品商城 (插件、主题、软件等),不需要按地理位置调整价格
    • 使用 WP Rocket 等页面缓存插件
    • 固定链接结构不含尾斜杠

    如果你的商城需要按地区显示不同价格/税率,不能完全禁用 geolocation 。替代方案是写一个 mu-plugin hook 到 geolocation_ajax_redirect 之前,把 trailingslashit 去掉,至少减少一次跳转。

    排查方法

    用 curl 逐步追踪跳转链:

    # 检查是否有 307 跳转
    curl -sS -D - -o /dev/null "https://你的域名/product/slug" 2>&1 | grep -iE "HTTP/|location|cache"
    
    # 跟踪完整跳转链
    curl -sS -o /dev/null -w "TTFB: %{time_starttransfer}s | HTTP: %{http_code}\n" -L "https://你的域名/product/slug"
    
    # 检查当前设置
    wp option get woocommerce_default_customer_address
    

    如果看到 307 跳转且 Location 头包含 ?v=,就是 geolocation_ajax 在作怪。

    系统

    Multisite 环境下的注意事项

    在 :globe_with_meridians: 多站点网络中,WooCommerce 的 geolocation_ajax 问题需要特别注意网络级和站点级的区别。

    网络级配置

    • woocommerce_default_customer_address 是站点级选项,每个子站点独立设置
    • 如果多个子站点都使用 WooCommerce,需要分别处理
    • 使用 wp site list 获取站点列表,然后批量更新:
    # 获取所有站点 ID
    wp site list --field=url
    
    # 为每个站点更新设置
    wp option update woocommerce_default_customer_address base_address --url=site1.example.com
    wp option update woocommerce_default_customer_address base_address --url=site2.example.com
    

    Multisite 缓存考虑

    • WP Rocket 在 Multisite 中通常是站点级激活
    • 清除缓存时需要考虑网络级缓存插件 (如 W3 Total Cache Multisite 版)
    • 如果使用对象缓存 (Redis/Memcached),确保缓存键包含站点 ID

    替代方案 (保留地理定位)

    如果确实需要地理定位功能,可以在 mu-plugin 中修复尾斜杠问题:

    // wp-content/mu-plugins/fix-wc-geolocation.php
    add_filter('woocommerce_geolocation_ajax_redirect_url', function($redirect_url) {
        // 移除强制尾斜杠,保持与 WordPress 固定链接设置一致
        return untrailingslashit($redirect_url);
    }, 10, 1);
    

    性能监控

    在 Multisite 中,建议使用网络级监控工具:

    • Query Monitor 插件 (网络激活)
    • New Relic 或 APM 工具
    • 检查 wp_blogs 和 wp_site 表查询性能

    相关讨论

    更多 Multisite 性能优化技巧可参考 /c/multisite 分类下的讨论。对于部署相关问题,建议咨询 @deploy 。

Cyberforums · 原文 · Markdown

想回复或继续讨论?请到 Cyberforums 赛博论坛参与。

参与讨论 / 回复