Skip to main content
Google Maps API 迁移指南(2026年5月截止):DirectionsService
Guides

Google Maps API 迁移指南(2026年5月截止):DirectionsService

DirectionsService、DistanceMatrixService、Heatmap Layer 和 Drawing Library 将于2026年5月从 Maps JavaScript API 中移除。完整迁移检查清单、替代 API 及成本对比,供开发者参考。

Brent van der Heiden16 min read
#Google Maps API#API Migration#Geocoding#Routing#Developer Guide

Google 多年来持续收紧 Maps Platform,而2026年5月的弃用浪潮是迄今影响最大的一次。Maps JavaScript API 将移除四项被广泛使用的功能:Heatmap Layer、Drawing Library、DirectionsService 和 DistanceMatrixService。如果你的应用依赖其中任何一项,在代码失效前只剩下几周时间完成迁移。

这不是那种旧接口会延续多年的「软弃用」。Google 设定了硬性移除日期,开发者控制台已经出现警告。本文详细说明变更内容、Google 的调整原因,以及如何通过可运行的代码示例完成各服务的迁移。如果需要即插即用的替代方案,我们也会展示 MapAtlas API 如何对应每个被弃用的 Google 服务。

弃用内容与时间表

受影响服务的完整时间表:

服务弃用时间移除日期替代方案(Google)
Heatmap Layer (Maps JS API)2025年8月2026年5月Maps Datasets API + deck.gl
Drawing Library (Maps JS API)2025年5月2026年5月Extended Component Library
DirectionsService (Maps JS API)2026年2月25日2026年5月Routes API (REST)
DistanceMatrixService (Maps JS API)2026年2月25日2026年5月Routes API (REST)

关键细节:Google 并非全面移除路由和距离计算功能,而是移除开发者使用了十余年的客户端 JavaScript 类,强制迁移至更新的 Routes API(服务端 REST 接口)。这不是简单的版本升级,而是将路由逻辑从浏览器迁移到后端的架构变更。

哪些代码会失效

如果代码库包含以下任意内容,在移除日期后将报错:

// All of these will stop working in May 2026
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();

移除后这些构造函数会抛出错误,没有任何回退机制,也不会优雅降级。地图能加载,但依赖这些类的所有功能会完全失效。

Google 为何强制推行这些变更

Google 的官方理由是性能提升和现代化改造。Routes API 作为 DirectionsService 和 DistanceMatrixService 的替代,支持旧版 JavaScript 类无法实现的新特性:环保路由、两轮车路由和过路费估算。

真正的驱动力是计费控制。将路由迁移到服务端 REST API 后,Google 可以实现更细粒度的计费和用量追踪。JavaScript 版 DirectionsService 允许客户端批量处理模式,Google 难以精确计量。Routes API 确保每个请求都经过可计量的接口。

对于 Heatmap Layer 和 Drawing Library,Google 正在推动开发者转向其 Extended Component Library 以及 deck.gl 等第三方可视化工具。这是一个更宏观趋势的体现:Google 将核心地图瓦片渲染保留在内部,其余功能外包给生态系统。

对开发者的实际影响:需要更多后端基础设施、管理更多 API 密钥,且新价格层的每请求成本在多数情况下更高。

迁移检查清单

编写任何迁移代码前,先完成以下检查清单:

1. 审查代码库

搜索代码库中对弃用类的引用:

# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|HeatmapLayer\|visualization.HeatmapLayer\|drawing.DrawingManager\|DrawingManager" \
  --include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/

记录每个使用这些服务的文件和组件,注明调用发生在客户端(浏览器)还是服务端渲染上下文(如 Next.js API 路由)中。

2. 梳理使用模式

针对每个使用点,记录:

  • 使用的出行方式(驾车、步行、骑行、公交)
  • 途经点支持(简单 A 到 B,还是多站点路线)
  • 消费的响应字段(距离、时长、折线、步骤、费用)
  • 请求量(每日/每月请求数,用于成本估算)
  • 延迟要求(面向用户的实时需求,还是批量处理)

3. 选择迁移目标

两个选项:

选项 A:继续使用 Google。 从弃用的 JavaScript 类迁移到新的 Google Routes API(REST)。需要后端改动、新的 API 密钥权限和账单更新。

选项 B:切换服务商。 迁移到第三方路由 API。由于集成代码无论如何都要重写,这是评估替代方案的好时机。

4. 搭建并行环境

绝对不要原地迁移。至少连续两周同时运行新旧实现,在切换前比较准确性和延迟表现。

5. 更新错误处理

弃用服务通过回调函数传递错误,REST API 替代方案返回 HTTP 状态码。错误处理逻辑需要相应调整。

逐 API 替换指南

DirectionsService 迁移至 MapAtlas Directions API

迁移前(Google,已弃用):

const directionsService = new google.maps.DirectionsService();

directionsService.route(
  {
    origin: { lat: 52.52, lng: 13.405 },
    destination: { lat: 48.8566, lng: 2.3522 },
    travelMode: google.maps.TravelMode.DRIVING,
    waypoints: [
      { location: { lat: 50.9375, lng: 6.9603 }, stopover: true }
    ],
  },
  (result, status) => {
    if (status === "OK") {
      const route = result.routes[0];
      console.log("Distance:", route.legs[0].distance.text);
      console.log("Duration:", route.legs[0].duration.text);
    }
  }
);

迁移后(MapAtlas Directions API):

const response = await fetch(
  "https://api.mapatlas.com/v1/directions?" +
    new URLSearchParams({
      origin: "52.52,13.405",
      destination: "48.8566,2.3522",
      waypoints: "50.9375,6.9603",
      mode: "driving",
      key: process.env.MAPATLAS_API_KEY!,
    })
);

const data = await response.json();

if (data.status === "OK") {
  const leg = data.routes[0].legs[0];
  console.log("Distance:", leg.distance.text);
  console.log("Duration:", leg.duration.text);
  // Polyline for map rendering
  const polyline = data.routes[0].overview_polyline;
}

主要差异:

  • 使用 REST 接口而非 JavaScript 类,调用来自后端而非浏览器。
  • 认证更简单,只需在查询参数或请求头中传入一个 API 密钥。
  • 响应结构相同,routes、legs、distance、duration 和 polyline 全部保留。

DistanceMatrixService 迁移至 MapAtlas Matrix API

迁移前(Google,已弃用):

const service = new google.maps.DistanceMatrixService();

service.getDistanceMatrix(
  {
    origins: [
      { lat: 52.52, lng: 13.405 },
      { lat: 48.1351, lng: 11.582 },
    ],
    destinations: [
      { lat: 48.8566, lng: 2.3522 },
      { lat: 51.5074, lng: -0.1278 },
    ],
    travelMode: google.maps.TravelMode.DRIVING,
  },
  (response, status) => {
    if (status === "OK") {
      response.rows.forEach((row, i) => {
        row.elements.forEach((element, j) => {
          console.log(`Origin ${i} -> Dest ${j}:`,
            element.distance.text, element.duration.text);
        });
      });
    }
  }
);

迁移后(MapAtlas Matrix API):

const response = await fetch("https://api.mapatlas.com/v1/matrix", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${process.env.MAPATLAS_API_KEY}`,
  },
  body: JSON.stringify({
    origins: [
      { lat: 52.52, lng: 13.405 },
      { lat: 48.1351, lng: 11.582 },
    ],
    destinations: [
      { lat: 48.8566, lng: 2.3522 },
      { lat: 51.5074, lng: -0.1278 },
    ],
    mode: "driving",
  }),
});

const data = await response.json();

data.rows.forEach((row: any, i: number) => {
  row.elements.forEach((element: any, j: number) => {
    console.log(`Origin ${i} -> Dest ${j}:`,
      element.distance.text, element.duration.text);
  });
});

响应结构几乎完全相同,主要变化是从基于回调的浏览器 API 切换为基于 Promise 的服务端 API。

Heatmap Layer 的替代方案

热力图可视化的迁移路径取决于具体需求:

方案一:MapLibre GL JS 热力图层(开源)

import maplibregl from "maplibre-gl";

const map = new maplibregl.Map({
  container: "map",
  style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
  center: [13.405, 52.52],
  zoom: 10,
});

map.on("load", () => {
  map.addSource("heat-data", {
    type: "geojson",
    data: {
      type: "FeatureCollection",
      features: heatmapPoints.map((point) => ({
        type: "Feature",
        geometry: { type: "Point", coordinates: [point.lng, point.lat] },
        properties: { weight: point.weight },
      })),
    },
  });

  map.addLayer({
    id: "heatmap-layer",
    type: "heatmap",
    source: "heat-data",
    paint: {
      "heatmap-weight": ["get", "weight"],
      "heatmap-intensity": 1,
      "heatmap-radius": 20,
      "heatmap-opacity": 0.7,
    },
  });
});

完全掌控热力图渲染,不依赖 Google 的瓦片服务器。

方案二:deck.gl HeatmapLayer(Google 官方推荐)

import { Deck } from "@deck.gl/core";
import { HeatmapLayer } from "@deck.gl/aggregation-layers";

const heatmapLayer = new HeatmapLayer({
  data: heatmapPoints,
  getPosition: (d) => [d.lng, d.lat],
  getWeight: (d) => d.weight,
  radiusPixels: 30,
});

两种方案均可行。MapLibre GL JS 与 MapAtlas 瓦片样式集成顺畅,deck.gl 则可叠加在任意底图上。

成本对比:Google Routes API vs MapAtlas

迁移至 Google 自己的 Routes API 不只是代码改动,还伴随新的价格体系:

服务Google(旧版,每1,000次)Google Routes API(每1,000次)MapAtlas(每1,000次)
Directions(基础)$5.00$5.00$1.50
Directions(高级,途经点/路况)$10.00$10.00$2.50
Distance Matrix(每元素)$5.00$5.00$1.00
Distance Matrix(高级)$10.00$10.00$2.00
Geocoding$5.00$5.00$1.50

每月10万次路由请求的费用:

  • Google Routes API: 约 $500-$1,000(取决于使用的功能)
  • MapAtlas Directions API: 约 $150-$250

对于同时使用路由、地理编码和距离计算的应用,成本差距快速累积。每月处理50万个矩阵元素的物流平台,使用 Google 约需 $2,500,使用 MapAtlas 仅需 $500。

完整价格详情请参阅 MapAtlas 定价页面

完整迁移示例:前后对比

以下是一个在地图上展示驾车路线的 React 组件完整迁移示例。

迁移前:React 中使用 Google Maps DirectionsService

import { useEffect, useRef } from "react";

function DirectionsMap({ origin, destination }: {
  origin: google.maps.LatLngLiteral;
  destination: google.maps.LatLngLiteral;
}) {
  const mapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const map = new google.maps.Map(mapRef.current!, {
      center: origin,
      zoom: 7,
    });

    const directionsRenderer = new google.maps.DirectionsRenderer();
    directionsRenderer.setMap(map);

    const directionsService = new google.maps.DirectionsService();
    directionsService.route(
      {
        origin,
        destination,
        travelMode: google.maps.TravelMode.DRIVING,
      },
      (result, status) => {
        if (status === "OK" && result) {
          directionsRenderer.setDirections(result);
        }
      }
    );
  }, [origin, destination]);

  return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}

迁移后:MapAtlas Directions API + MapLibre GL JS

import { useEffect, useRef } from "react";
import maplibregl from "maplibre-gl";

function DirectionsMap({ origin, destination }: {
  origin: { lat: number; lng: number };
  destination: { lat: number; lng: number };
}) {
  const mapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const map = new maplibregl.Map({
      container: mapRef.current!,
      style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
      center: [origin.lng, origin.lat],
      zoom: 7,
    });

    map.on("load", async () => {
      // Fetch directions from your backend (or directly if CORS allows)
      const res = await fetch(
        `/api/directions?` +
          new URLSearchParams({
            origin: `${origin.lat},${origin.lng}`,
            destination: `${destination.lat},${destination.lng}`,
            mode: "driving",
          })
      );
      const data = await res.json();

      if (data.routes?.[0]) {
        const coordinates = data.routes[0].geometry.coordinates;

        map.addSource("route", {
          type: "geojson",
          data: {
            type: "Feature",
            geometry: { type: "LineString", coordinates },
            properties: {},
          },
        });

        map.addLayer({
          id: "route-line",
          type: "line",
          source: "route",
          paint: {
            "line-color": "#4A90D9",
            "line-width": 5,
          },
        });

        // Fit map to route bounds
        const bounds = coordinates.reduce(
          (b: maplibregl.LngLatBounds, coord: [number, number]) =>
            b.extend(coord),
          new maplibregl.LngLatBounds(coordinates[0], coordinates[0])
        );
        map.fitBounds(bounds, { padding: 50 });
      }
    });

    return () => map.remove();
  }, [origin, destination]);

  return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}

后端 API 路由(Next.js)

// app/api/directions/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const origin = searchParams.get("origin");
  const destination = searchParams.get("destination");
  const mode = searchParams.get("mode") || "driving";

  const response = await fetch(
    `https://api.mapatlas.com/v1/directions?` +
      new URLSearchParams({
        origin: origin!,
        destination: destination!,
        mode,
        key: process.env.MAPATLAS_API_KEY!,
      })
  );

  const data = await response.json();
  return NextResponse.json(data);
}

这种模式将 API 密钥保留在服务端,仅向客户端暴露路线几何数据。

截止日期前如何测试迁移

第一步:并行运行两套 API

切换前的两周内,对每个请求同时调用旧版 Google 服务和新替代服务,记录并比较两份响应:

async function getDirectionsWithComparison(
  origin: string,
  destination: string
) {
  const [googleResult, mapatResult] = await Promise.all([
    fetchGoogleDirections(origin, destination),
    fetchMapAtlasDirections(origin, destination),
  ]);

  // Compare key metrics
  const distanceDelta = Math.abs(
    googleResult.distance - mapatResult.distance
  );
  const durationDelta = Math.abs(
    googleResult.duration - mapatResult.duration
  );

  console.log({
    route: `${origin} -> ${destination}`,
    googleDistance: googleResult.distance,
    mapatDistance: mapatResult.distance,
    distanceDeltaPercent: ((distanceDelta / googleResult.distance) * 100).toFixed(1),
    googleDuration: googleResult.duration,
    mapatDuration: mapatResult.duration,
    durationDeltaPercent: ((durationDelta / googleResult.duration) * 100).toFixed(1),
  });

  // Use MapAtlas result in production, Google as validation
  return mapatResult;
}

第二步:配置功能开关

使用功能开关控制应用调用哪套 API,便于出现问题时立即回滚:

const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";

const directions = useMapAtlasDirections
  ? await fetchMapAtlasDirections(origin, destination)
  : await fetchGoogleDirections(origin, destination);

第三步:监控错误率

切换后重点关注:

  • 新 API 的 HTTP 4xx/5xx 错误率
  • 延迟增加(新服务商的响应时间可能不同)
  • 响应中 缺失的字段(UI 依赖项)
  • 边缘场景的路线准确性(轮渡路线、收费公路、限行区域)

第四步:上线前进行压力测试

如果应用存在流量峰值(例如物流平台的早高峰调度),以峰值流量的2倍对新 API 进行压力测试。MapAtlas 提供沙盒环境,可在不产生生产计费的情况下完成压力测试。

行动时间表:本周该做什么

如果尚未开始迁移,按以下优先顺序推进:

  1. 本周: 审查代码库,找出所有使用这四项弃用服务的位置。
  2. 第2周: 注册 MapAtlas 账户并获取 API 密钥。免费层包含10,000次测试请求。
  3. 第3周: 为最关键的服务(通常是 DirectionsService)实现替代方案。
  4. 第4周: 迁移其余服务并进行并行测试。
  5. 5月截止日期前: 完成切换,移除 Google API 依赖,更新账单配置。

迁移不是可选项。2026年5月后,弃用类将从 Maps JavaScript API 中移除,任何引用这些类的代码都会在运行时抛出错误。现在开始,有充足时间做好测试;等到最后一周,只能在压力下紧急修复生产环境。

需要迁移支持,MapAtlas 提供直接的开发者协助。通过联系页面联系我们,或从 API 文档开始,根据你的需求评估替代 API。

常见问题

DirectionsService 和 DistanceMatrixService 何时从 Google Maps API 中移除?

Heatmap Layer 和 Drawing Library 分别于2025年8月和5月弃用,计划2026年5月移除。DirectionsService 和 DistanceMatrixService 于2026年2月25日弃用,移除目标相同。移除后,对这些服务的 API 调用将直接返回错误,不存在任何降级处理。

我现有的 Google Maps JavaScript API 密钥在2026年5月后还能用吗?

密钥对未弃用的服务仍然有效。但通过 Maps JavaScript API 调用 DirectionsService、DistanceMatrixService、Heatmap Layer 或 Drawing Library 的代码,将在移除日期后完全失效。必须在截止日期前将这些调用迁移到替代 API。

Google Maps Directions API 最经济的替代方案是什么?

MapAtlas 提供的 Directions API 费用约比 Google 同类产品低70%。免费层每月包含10,000次请求,足以支撑迁移开发和测试。MapAtlas 的请求/响应格式与 Google 最为接近,可显著降低迁移工作量。

可以分阶段迁移,还是必须一次性切换?

完全可以分阶段迁移,这也是推荐做法。每个弃用服务相互独立:先替换 DirectionsService,再替换 DistanceMatrixService,最后处理可视化库。每个替换均可单独验证后再推进下一步。

MapAtlas 是否支持与 Google DirectionsService 相同的途经点和出行方式?

支持。MapAtlas Directions API 支持驾车、步行和骑行模式,以及中间途经点。请求格式略有不同(RESTful 接口而非 JavaScript 类),但核心功能,即带出行方式选择的多站点路由,完全等价。

觉得有用?分享给他人吧。

关于作者

Brent van der Heiden

作者

Brent van der Heiden

Co-Founder & CEO at MapAtlas

Brent built MapAtlas out of a conviction that developers deserve location APIs with fair pricing and genuine end-user privacy. He writes about geospatial infrastructure, AI search visibility, and how location data powers the products people rely on every day.

查看所有文章
返回博客