这是一个非常实用的功能,尤其对于本地生活服务类网站,核心思路是:获取访客的 IP 地址 -> 通过 IP 地理位置库查询该 IP 所在城市 -> 根据城市信息,自动将用户重定向或引导到对应的子站点(如 city1.example.com 或 www.example.com/city1/)。

下面我将提供两种主流的实现方案,并详细说明其优缺点和具体步骤。
基于 JavaScript 的前端重定向(推荐)
这是目前最常用、最灵活且对服务器压力最小的方法,它利用 JavaScript 在用户浏览器端执行,不占用服务器 PHP 资源。
原理
- 在网站的公共页面模板(如
head.htm)中嵌入一段 JavaScript 代码。 - 该 JS 代码在页面加载时,通过调用一个公开的 IP 地理位置查询 API(如淘宝、新浪等),获取当前访客的 IP 和城市信息。
- 获取到城市后,JS 判断是否存在对应的分站链接。
- 如果存在,则使用
window.location.href进行页面跳转;如果不存在,则不做任何操作,留在当前网站。
优点
- 性能高:不增加服务器 PHP 的负担,计算和跳转都在客户端完成。
- 实现简单:只需修改模板文件,无需修改核心程序,升级 DedeCMS 时不易丢失。
- 灵活性高:可以轻松地在前端添加弹窗提示、延迟跳转等交互效果,提升用户体验。
缺点
- 依赖第三方 API:API 服务不稳定或收费,功能会受影响。
- 首次加载有延迟:JS 需要从外部 API 获取数据,可能会有几百毫秒的延迟,导致用户先看到主站,然后才跳转。
- 可能被浏览器或插件拦截:少数情况下,广告拦截器或安全策略可能会阻止对外部 API 的请求。
详细实施步骤(方案一)
第一步:准备 IP 地理位置查询 API
这里我们以淘宝 IP 库为例,它免费且稳定,API 地址为:http://ip.taobao.com/service/getIpInfo.php?ip=[访客IP]

返回的 JSON 数据示例:
{
"code": 0,
"data": {
"ip": "123.123.123.123",
"country": "中国",
"area": "",
"region": "浙江省",
"city": "杭州市",
"county": "",
"isp": "电信",
"country_id": "CN",
"area_id": "",
"region_id": "330000",
"city_id": "330100",
"county_id": "",
"isp_id": "100017"
}
}
我们需要其中的 region(省份)和 city(城市)字段。
第二步:获取分站映射规则
你需要提前规划好城市和分站 URL 的对应关系。
- 浙江省 -> 杭州市 ->
hz.example.com - 广东省 -> 深圳市 ->
sz.example.com - 北京市 ->
bj.example.com - 其他城市 -> 默认站
www.example.com
第三步:修改网站公共模板
登录 DedeCMS 后台,模板 -> 默认模板管理 -> 选择你的模板集 -> head.htm。
在 <head> 和 </head> 标签之间,添加以下 JavaScript 代码:
<script type="text/javascript">
// 城市与分站的映射关系
// 格式: "城市名": "分站URL", 注意城市名要和API返回的完全一致(包括省份,如“杭州市”)
var citySites = {
"杭州市": "http://hz.example.com",
"深圳市": "http://sz.example.com",
"北京市": "http://bj.example.com"
// 可以继续添加更多城市...
};
// 默认站点URL(当没有匹配到城市时使用)
var defaultSite = "http://www.example.com";
// 获取IP的函数
function getIP() {
return fetch('https://api.ipify.org?format=json')
.then(response => response.json())
.then(data => data.ip)
.catch(error => {
console.error('获取IP失败:', error);
return null; // 如果获取IP失败,则不进行跳转
});
}
// 根据IP获取城市并跳转
function redirectByIP() {
getIP().then(ip => {
if (!ip) return;
// 使用淘宝IP查询API
const apiUrl = `http://ip.taobao.com/service/getIpInfo.php?ip=${ip}`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
// 检查API是否成功返回数据
if (data.code === 0) {
const cityName = data.data.city; // 获取城市名
console.log("当前访客所在城市: " + cityName);
// 检查城市是否在映射表中
if (citySites[cityName]) {
// 可选:添加延迟跳转,给用户一个提示
// setTimeout(function() {
// window.location.href = citySites[cityName];
// }, 2000); // 2秒后跳转
// 直接跳转
window.location.href = citySites[cityName];
}
} else {
console.error("IP查询API错误:", data.msg);
}
})
.catch(error => {
console.error('查询城市信息失败:', error);
});
});
}
// 页面加载完成后执行
window.onload = redirectByIP;
</script>
代码说明:
citySites对象:请务必将这里的城市名和URL修改成你自己的。defaultSite:定义了默认的网站地址。getIP():这个函数使用ipify.org这个服务来获取访客的真实公网 IP,这是比让后端 PHP 获取更可靠的方式。redirectByIP():核心逻辑,先获取 IP,再调用淘宝 API 获取城市,最后进行匹配和跳转。window.onload = redirectByIP;:确保页面所有元素加载完毕后再执行我们的跳转逻辑。
第四步:清空缓存并测试
- 在 DedeCMS 后台,
系统->一键更新缓存,清空所有缓存。 - 使用不同地区的网络访问你的网站,观察是否自动跳转到了对应的分站。
基于 PHP 的后端重定向
这种方法在服务器端 PHP 代码层面完成 IP 判断和跳转。
原理
- 在 DedeCMS 的全局入口文件
index.php的最顶部,加入 PHP 代码。 - PHP 代码首先获取访客的 IP 地址。
- 调用本地的 IP 数据库(如纯真 IP 库)或 API 来查询城市。
- 根据查询结果,使用
header("Location: ...");进行页面跳转。
优点
- 跳转速度快:在服务器端完成,用户感知不到延迟。
- 对用户透明:跳转在浏览器渲染页面之前完成,用户体验更流畅。
缺点
- 增加服务器负担:每次页面请求,PHP 都要执行 IP 查询逻辑,会消耗一定的 CPU 和内存资源。
- 实现复杂:需要修改核心文件,DedeCMS 升级时可能需要重新修改。
- 灵活性差:难以实现前端交互,如弹窗提示。
详细实施步骤(方案二)
准备工作:获取 IP 地理位置库
- 下载纯真 IP 库:从
https://github.com/lionsoul2025/ip2region下载最新的ip2region.xdb文件,这是一个性能极高的 IP 数据库。 - 上传数据库:将
ip2region.xdb文件上传到你的网站根目录或一个专门的目录,/data/。
第一步:安装 PHP 扩展(推荐)
为了获得最佳性能,建议安装 ip2region 的 PHP 扩展,但这需要编译和安装,对虚拟主机用户可能不友好,如果无法安装扩展,请直接跳到第二步,使用纯 PHP 版本。
第二步:修改 index.php 文件
用 FTP 或服务器管理工具打开网站根目录下的 index.php 文件,在 <?php 这行代码的正下方,添加如下 PHP 代码:
<?php
/**
* 在这里添加按IP切换城市的代码
*/
require_once __DIR__ . '/path/to/ip2region.php'; // 引入ip2region的PHP查询类库
// 城市与分站的映射关系
$citySites = [
'杭州市' => 'http://hz.example.com',
'深圳市' => 'http://sz.example.com',
'北京市' => 'http://bj.example.com'
];
// 默认站点URL
$defaultSite = 'http://www.example.com';
// 获取真实访客IP
function getRealIpAddr() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 注意:X-Forwarded-For 可能是多个IP,第一个是真实IP
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
} else {
$ip = '0.0.0.0';
}
return $ip;
}
// 执行跳转逻辑
try {
$ip = getRealIpAddr();
if ($ip == '0.0.0.0') {
throw new Exception("无法获取IP地址");
}
// --- 使用 ip2region 进行查询 (推荐) ---
$dbPath = __DIR__ . '/data/ip2region.xdb'; // 数据库文件路径
$searcher = new \ip2region\Ip2region($dbPath);
$regionInfo = $searcher->search($ip);
// 解析查询结果,格式如:中国|0|浙江省|杭州市|电信
$region = $regionInfo['region'];
$city = explode('|', $region)[3]; // 第四个元素是城市
// --- 或者使用淘宝API (不推荐,性能差) ---
// $apiUrl = "http://ip.taobao.com/service/getIpInfo.php?ip={$ip}";
// $response = file_get_contents($apiUrl);
// $data = json_decode($response, true);
// if ($data['code'] == 0) {
// $city = $data['data']['city'];
// } else {
// throw new Exception("IP查询失败");
// }
if (isset($citySites[$city])) {
// 如果找到匹配的城市,则进行重定向
// header("Location: " . $citySites[$city]);
// exit; // 必须使用 exit 来停止后续代码的执行
// 为了调试,可以先 echo 出来,确认是否正确
echo "检测到城市: " . $city . "<br>";
echo "准备跳转到: " . $citySites[$city];
// 取消下面这行的注释,以启用真正的跳转
// header("Location: " . $citySites[$city]);
// exit;
}
} catch (Exception $e) {
// 如果发生任何错误(如IP获取失败、查询失败),则跳转到默认站点或什么都不做
// header("Location: " . $defaultSite);
// exit;
}
// --- DedeCMS 原有代码 ---
require_once (dirname(__FILE__) . "/include/common.inc.php");
require_once DEDEINC."/arc.partview.class.php";
代码说明:
- 路径配置:请确保
$dbPath和require_once的路径正确指向你的ip2region.xdb文件和Ip2region类库文件。 - IP 获取函数:
getRealIpAddr()是一个健壮的获取真实 IP 的函数,能处理代理服务器等情况。 - 查询逻辑:代码中展示了两种查询方式:高性能的
ip2region本地数据库和方便但性能较差的淘宝 API。强烈推荐使用ip2region。 - 调试:在
header("Location: ...");上面,我先用echo输出结果,你可以先访问网站,查看源码,确认获取到的城市是否正确,确认无误后,再取消header和exit的注释,启用真正的跳转。 - 错误处理:使用
try...catch捕获可能发生的异常,防止程序因错误而中断。
第三步:清空缓存并测试
与方案一相同,清空 DedeCMS 缓存,并用不同网络环境进行测试。
总结与建议
| 特性 | 方案一 (JS 前端) | 方案二 (PHP 后端) |
|---|---|---|
| 性能 | 高,不占用服务器资源 | 较低,每次请求都需查询 |
| 实现难度 | 简单,改模板即可 | 复杂,需改核心文件,依赖IP库 |
| 维护性 | 好,升级DedeCMS不受影响 | 差,升级后可能被覆盖 |
| 用户体验 | 可能有轻微延迟,可做交互 | 无延迟,体验流畅 |
| 灵活性 | 高,易于实现弹窗、延迟等 | 低,逻辑固定在服务端 |
最终建议:
对于绝大多数网站,强烈推荐使用方案一(JavaScript 前端重定向),它在性能、实现难度和维护性上取得了很好的平衡,并且可以提供更好的用户体验(可以弹出一个提示:“检测到您来自杭州,即将跳转到杭州分站...[3秒后自动跳转][取消]”)。
只有当你的网站流量极大,且对跳转延迟有极致要求,并且你有能力维护服务器环境时,才考虑方案二。
