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

如何基于IP地址实现访客分向10个不同URL的纯JS方案?

问题

我希望将访问网站的每位用户定向至不同URL,最多设置10个目标地址。规则如下:

  • 第1位访客访问www.youarelovely.com时直接打开该站点
  • 第2位访客重定向至www.youarelovely.com/1
  • 第3位访客重定向至www.youarelovely.com/2
  • ……以此类推至第10个地址www.youarelovely.com/9

需求:

  • 通过检测用户IP地址并存储映射关系,已有IP访客直接定向至对应URL,新IP分配下一个可用地址
  • 仅用纯HTML和JavaScript实现,部署在GitHub Pages或Codepen,为概念验证项目,无需复杂实现
  • 非地域重定向,所有访客地域相同
核心限制与解决方案

纯前端HTML/JS在静态托管环境(如GitHub Pages)下无法直接读写服务器文本文件,因为前端没有服务器文件系统权限。因此需要借助两个公共API实现核心功能:

  1. 免费IP查询API:获取用户公网IP
  2. 免费键值存储API:替代文本文件存储IP与路径的全局映射

以下是概念验证的实现代码:

实现代码
// 基础配置
const BASE_URL = 'https://www.youarelovely.com';
const MAX_ALLOCATIONS = 10; // 最多10个目标地址
// 替换为你的键值存储API端点(如Firebase Realtime Database、Supabase REST接口)
const STORAGE_ENDPOINT = 'https://your-storage-service.example.com/ip-mappings';

// 获取用户公网IP
async function getPublicIp() {
  try {
    const res = await fetch('https://ipapi.co/ip/');
    if (!res.ok) throw new Error(`HTTP错误: ${res.status}`);
    return await res.text();
  } catch (err) {
    console.error('获取IP失败:', err);
    // 失败时返回随机模拟ID,仅用于本地测试
    return `test-${Math.random().toString(36).substring(2, 10)}`;
  }
}

// 查询IP对应的已分配路径
async function getAssignedPath(ip) {
  try {
    const res = await fetch(`${STORAGE_ENDPOINT}/${ip}`);
    if (res.ok) {
      const data = await res.json();
      return data.path;
    } else if (res.status === 404) {
      return null; // IP未被分配
    }
    throw new Error(`查询映射失败: ${res.status}`);
  } catch (err) {
    console.error('查询IP映射出错:', err);
    return null;
  }
}

// 为新IP分配路径并存储映射
async function allocateNewPath(ip) {
  try {
    // 获取所有已分配的映射,统计数量
    const res = await fetch(STORAGE_ENDPOINT);
    if (!res.ok) throw new Error(`获取映射列表失败: ${res.status}`);
    const allMappings = await res.json();
    const allocatedCount = Object.keys(allMappings).length;

    if (allocatedCount >= MAX_ALLOCATIONS) {
      // 已满10个分配,返回默认主站路径
      return '';
    }

    // 分配规则:第1个是''(主站),第2个是'1',...第10个是'9'
    const newPath = allocatedCount === 0 ? '' : `${allocatedCount - 1}`;
    // 存储新的IP-路径映射
    await fetch(`${STORAGE_ENDPOINT}/${ip}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ path: newPath })
    });
    return newPath;
  } catch (err) {
    console.error('分配路径失败:', err);
    return ''; // 失败时返回主站
  }
}

// 主重定向逻辑
async function handleRedirect() {
  const userIp = await getPublicIp();
  let targetPath = await getAssignedPath(userIp);

  if (!targetPath) {
    targetPath = await allocateNewPath(userIp);
  }

  const targetUrl = targetPath ? `${BASE_URL}/${targetPath}` : BASE_URL;
  if (window.location.href !== targetUrl) {
    console.log(`重定向至: ${targetUrl}`);
    window.location.href = targetUrl;
  } else {
    console.log('已处于目标页面');
  }
}

// 页面加载时执行
window.addEventListener('load', handleRedirect);
关键说明
  1. 存储API配置:你需要自己搭建或使用免费的键值存储服务(如Firebase Realtime Database),替换代码中的STORAGE_ENDPOINT,这类服务提供的免费额度足够支撑概念验证。
  2. IP查询API备选:如果ipapi.co请求受限,可替换为https://api.ipify.org/等其他免费IP查询服务。
  3. 本地模拟方案:若无法使用外部存储API,可改用localStorage替代,但该方案仅在同一浏览器内有效,无法实现跨设备的全局IP分配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:06:13