PAYATHON 2026

Google Maps API Places Library 的 Quota limits

支付小周

结论

按照题述规则,通过 Maps JavaScript API 加载 places library,并在浏览器中调用 google.maps.places.PlacesService,不受 Places API Web Service 每日 100,000 次、按 API key 统计的固定总量限制。

当时,这类请求按 end-user 分配额度。即使 JavaScript 应用的所有用户共用一个 API key,搜索请求也不会全部累计到同一个 Web Service quota 中。因此,Google API Console 中的 Places Web Service quota 没有增加,通常是因为两种调用方式采用了不同的计量机制。

不过,不能据此得出下面的计算公式:

应用总额度 = 100,000 × 用户数

100,000 是已验证项目调用 Places API Web Service 时的项目级额度,并非每位 JavaScript end-user 都能获得的额度。end-user 的识别和限流机制也不能简单理解为“每个 unique IP 对应一个 quota”。

还需要注意,题述 FAQ、Text Search 的 10-times multiplier、Radar Search、Place Bumps,以及“信用卡只用于验证、不收费”等内容都属于旧版 Places API 政策。Google Maps Platform 后来改为按 SKU、账单账户和项目配额管理。维护现有系统时,应以当前 Google Cloud Console 显示的 quota 和 billing SKU 为准,不要继续使用这些旧规则预测成本。

为什么两种请求的统计结果不同

下面的 URL 直接调用 Places API Web Service:

https://maps.googleapis.com/maps/api/place/nearbysearch/json

例如:

https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=XXXX

应用的 API key 会标识该请求,因此请求会计入对应项目的 Places API Web Service quota。

下面的代码则调用 Maps JavaScript API 的 Places library:

<script
  src="https://maps.googleapis.com/maps/api/js?key=XXX&libraries=places">
</script>
const service = new google.maps.places.PlacesService(map);

service.textSearch(request, callback);

按照题述时期的政策,这些请求由 Places library 代表浏览器终端用户发起,使用 end-user quota,而不是同一 API key 下的 Web Service 项目级请求池。因此,它们不会以相同方式出现在 Places Web Service 的 quota count 中。

这不代表 Google 没有记录这些请求,也不代表该服务没有任何限制。它们只是没有计入所观察的那项 Web Service quota。

推荐的调用方式

纯浏览器应用可以继续通过 JavaScript library 调用搜索和详情接口:

const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: -33.8670522, lng: 151.1957362 },
  zoom: 15
});

const service = new google.maps.places.PlacesService(map);

service.textSearch(
  {
    query: "food near harbour",
    location: map.getCenter(),
    radius: 500
  },
  (results, status) => {
    if (status !== google.maps.places.PlacesServiceStatus.OK) {
      console.error("Places search failed:", status);
      return;
    }

    console.log(results);
  }
);

需要地点详情时,使用搜索结果中的 place ID:

service.getDetails(
  {
    placeId: selectedPlaceId,
    fields: ["name", "formatted_address", "geometry", "photos"]
  },
  (place, status) => {
    if (status !== google.maps.places.PlacesServiceStatus.OK) {
      console.error("Place details failed:", status);
      return;
    }

    console.log(place);
  }
);

如果详情结果包含照片,可以通过 library 返回的照片对象生成 URL:

const photoUrl = place.photos?.[0]?.getUrl({
  maxWidth: 800,
  maxHeight: 600
});

只请求实际需要的详情字段。即使旧版额度不是按项目汇总,减少不必要的 getDetails 调用也能降低限流风险。在当前计费模型中,字段选择还可能影响对应的 SKU 和费用。

如何确认生产环境的实际限制

问题引用的是历史政策,因此上线前需要根据当前项目配置重新核对:

  1. 在 Google Cloud Console 中确认项目启用的是 Maps JavaScript API、Places API,还是 Places API (New)。
  2. 分别检查相关 API 的 Metrics 和 Quotas 页面,不要只看旧 Places Web Service 的单一 quota counter。
  3. 在 Billing 报表中按 SKU 查看搜索、详情、照片和 Maps JavaScript API 的实际用量。
  4. 为浏览器 API key 配置 HTTP referrer restrictions,并且只允许调用需要的 API。
  5. 设置预算提醒和 quota 告警,不要把“控制台计数未增加”误判为“不会计费或永不限流”。
  6. 记录 OVER_QUERY_LIMIT、RESOURCE_EXHAUSTED 等状态,并做好降级处理。

注意事项

  • end-user 并不等同于一个公开承诺的 unique IP。Google 可能结合客户端、会话、项目和反滥用信号进行识别,具体算法通常不会作为可依赖的接口契约公开。
  • NAT、代理、企业网络和共享出口都会使“按 IP 计算用户数”的结果失真。
  • 不能把 JavaScript library 当作绕过 quota 或 billing 的方式,也不要用它代理服务器端批量查询。
  • Web Service 请求和 JavaScript library 请求采用不同的调用路径,配额指标、SKU 和控制台统计可能也不同。
  • 在旧规则下,JavaScript Places library 不存在 100,000 × 用户数 这样可以直接计算的总额度。在当前规则下,也应根据项目实际使用的 SKU、quota 和账单配置判断,不能套用旧 FAQ 中的 multiplier。

备注:内容仅供参考。