You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloudflare Workers:仅首次访问地理重定向 后续遵循会话语言

Cloudflare Workers 首次访问地域重定向改造方案

核心改造逻辑

现有代码未做访问状态校验,所有请求都会直接触发重定向,且使用301永久重定向会被浏览器缓存,进一步导致跳转逻辑异常。改造通过Cookie做状态标记,逻辑如下:

  • 所有请求进入时先校验是否存在专属标识Cookie geo_redirected
    • 存在该Cookie:说明用户已经完成首次跳转/手动选择过站点版本,直接放行原请求,不做任何地域强制跳转
    • 不存在该Cookie:匹配IP归属地得到目标站点地址
      • 如果当前请求地址已经和目标地址一致:直接返回源站内容,同时写入标识Cookie,避免死循环
      • 如果当前请求地址和目标地址不一致:返回302临时重定向到目标地址,同时在响应头写入标识Cookie,后续用户访问将不再触发强制跳转

Cookie配置说明

标识Cookie采用以下配置,兼顾可用性和浏览器兼容性:

  • Cookie名:geo_redirected
  • 值:1(标记已完成首次跳转)
  • 有效期:Max-Age=2592000 即30天,可根据需求自行调整时长
  • 生效范围:Path=/ 全站所有路径生效
  • 安全属性:SameSite=Lax 适配现代浏览器跨站安全规则

改造后完整代码

// 各国家/地区对应跳转路径
var sg_countries = ['SG', 'TH', 'MY', 'VN', 'RI', 'RP', 'LA', 'BN'];
var jp_countries = ['JP'];
var gr_countries = ['GR'];
var kr_countries = ['KR'];
var zh_sg_countries = ['TW', 'HK', 'CN'];

// 标识Cookie配置
const REDIRECT_COOKIE = 'geo_redirected=1; Max-Age=2592000; Path=/; SameSite=Lax';

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

function inArray(needle, haystack) {
  var length = haystack.length;
  for (var i = 0; i < length; i++) {
    if (haystack[i] == needle) return true;
  }
  return false;
}

function mapCountry(country_code) {
  if (inArray(country_code, sg_countries)) {
    return 'https://ofdreams.com/sg';
  }
  if (inArray(country_code, jp_countries)) {
    return 'https://ofdreams.com/jp';
  }
  if (inArray(country_code, gr_countries)) {
    return 'https://ofdreams.com/gr';
  }
  if (inArray(country_code, kr_countries)) {
    return 'https://ofdreams.com/kr';
  }
  if (inArray(country_code, zh_sg_countries)) {
    return 'https://ofdreams.com/zh-sg';
  }
  // 默认跳转至US站点
  return 'https://ofdreams.com';
}

async function handleRequest(request) {
  const url = new URL(request.url);
  // 读取请求携带的Cookie
  const cookie = request.headers.get('Cookie') || '';
  
  // 存在已跳转标识,直接放行原请求
  if (cookie.includes('geo_redirected=1')) {
    return fetch(request);
  }

  // 匹配当前IP归属地对应的目标地址
  const targetUrl = mapCountry(request.headers.get('CF-IPCountry'));
  const target = new URL(targetUrl);

  // 当前访问路径已经和目标地域路径一致,直接返回内容并写入Cookie
  if (url.pathname === target.pathname && url.origin === target.origin) {
    const response = await fetch(request);
    const newResponse = new Response(response.body, response);
    newResponse.headers.append('Set-Cookie', REDIRECT_COOKIE);
    return newResponse;
  }

  // 首次访问且路径不匹配,返回302临时跳转并写入Cookie
  return new Response('', {
    status: 302,
    headers: {
      'Location': targetUrl,
      'Set-Cookie': REDIRECT_COOKIE,
      'Cache-Control': 'no-store' // 禁止浏览器缓存跳转响应,避免异常
    }
  })
}

注意事项

  • 原代码使用的301永久重定向会被浏览器本地强缓存,测试前请清空浏览器缓存,避免旧缓存逻辑影响效果
  • 如果站点存在手动切换语言/站点版本的功能,只需要在用户手动切换时,重新设置该Cookie(可将值改为用户选择的版本标识),即可完全尊重用户自主选择,不会再触发地域强制跳转
  • 如果需要Cookie仅在HTTPS环境下生效,可在Cookie配置中追加Secure属性

内容的提问来源于stack exchange,提问作者tecne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:45:44