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

如何捕获Google Maps API访问KML文件的所有IP地址

问题:捕获Google Maps API访问KML的所有IP地址

问题背景

我刚接触Google Maps API与KML处理,在网站上通过API展示服务器上的KML文件,希望捕获所有访问KML文件的客户端IP,但发现Apache日志遗漏了部分IP。

最初的解决方案(.htaccess + access.php)

配置.htaccess将未携带指定Cookie的请求转发到access.php:

RewriteEngine On

RewriteCond %{HTTP_COOKIE} !fla=[^;]+ [NC]
RewriteRule ^(.*)$ access.php?url=https://%{HTTP_HOST}%{REQUEST_URI} [L,QSA]

access.php负责记录IP、设置Cookie并跳转至目标KML:

<?php
    $file = fopen('ips.txt', 'a+');
    fwrite($file, $_SERVER['REMOTE_ADDR'] . "\n");
    fclose($file);

    setcookie("fla", hash("sha512", random_bytes(10)), time() + 30, "", "", 1);
    header("Location: ". $_GET['url']);
?>

测试发现:客户端直接访问KML文件时能正常捕获IP,但Google Maps API仅在首次解析KML时记录IP,后续加载KML无法捕获Google的源IP,只有重命名KML文件名后才会再次记录。

优化后的方案(servefile.php)

将逻辑整合到单个servefile.php,增加X-Forwarded-For检测,移除.htaccess和access.php:

<?php
    header("X-Frame-Options: deny");
    header("X-XSS-Protection: 1; mode=block");
    header("Strict-Transport-Security: Max-Age=31536000; includeSubDomains");
    header("X-Content-Type-Options: nosniff");
    header("Cache-Control: no-cache, no-store, must-revalidate");
    header("Pragma: no-cache");
    header("Referrer-Policy: no-referrer");

    $ip_file = fopen('ips.txt', 'a+');
    
    if (isset($_SERVER['HTTP_CLIENT_IP']) && array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
        $ip_addr = $_SERVER['HTTP_CLIENT_IP'];
    } else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
        $x_fwd_ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $x_fwd_ips = array_map('trim', $x_fwd_ips);
        $ip_addr = $x_fwd_ips[0];
    } else {
        $ip_addr = $_SERVER['REMOTE_ADDR'];
    }

    fwrite($ip_file, $ip_addr . "\n");
    fclose($ip_file);

    // redacted for security reasons; it is present in the live code
    $base_url = "";

    $file = $base_url . "" . $_GET['url'];
    $filename = $_GET['url'];

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('Content-Transfer-Encoding: binary');
    header('Accept-Ranges: bytes');

    @readfile($file);
?>

问题依旧:客户端直接访问文件时能捕获IP,而加载Google地图时仅首次加载KML能捕获IP。


核心原因

Google Maps API会缓存已解析的KML资源,后续请求直接从Google的CDN或缓存服务器读取,不会再向你的服务器发起请求,因此无法捕获后续的IP。重命名KML相当于生成新的资源URL,会触发Google重新请求,所以能再次记录IP。


解决方法

1. 给KML请求添加动态参数(最有效)

在调用Google Maps API加载KML时,为URL添加唯一动态参数(比如时间戳、随机字符串),让每次请求的URL都不同,绕过Google的缓存。

  • 示例:将KML加载URL从 https://your-server.com/your.kml 修改为:
    // 前端或后端生成带时间戳的URL
    $kmlUrl = "https://your-server.com/servefile.php?url=your.kml&t=" . time();
    
  • 每次请求的URL都是唯一的,Google会重新向你的服务器发起请求,确保每次访问都能被记录IP。

2. 强化缓存控制响应头

虽然已设置no-cache类头,但Google的缓存机制可能忽略这些指令,可进一步优化:
修改servefile.php中的缓存头部分:

header("Cache-Control: private, no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: 0"); // 设置过期时间为过去,强制不缓存

private指令明确告诉缓存服务器(包括Google的)该资源为私有,不能共享缓存。

3. 前端主动触发KML刷新(配合地图逻辑)

如果需要在特定场景下(比如地图刷新、内容更新)重新加载KML,可在前端调用Google Maps的fetchKml()方法,同时携带新的动态参数,确保每次请求都触发服务器记录。

4. 区分Google服务器IP与客户端真实IP

注意:Google Maps API请求KML时,发起请求的IP是Google服务器的IP,而非客户端真实IP。若要捕获客户端真实IP,需通过前端上报:

  • 在页面加载时,用JavaScript获取客户端IP(可通过后端接口配合),然后发送到你的服务器记录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:09:50