mcpField
G
google-maps-api

google-maps-api

github.com/tivojn其他6403 次安装36 周前更新
代码仓库

关于 google-maps-api

google-maps-api 是用于调用 Google Maps Platform REST API 并获取结构化 JSON 的命令行技能,涵盖地图、路线、地点、环境和地理空间服务;需要 API 密钥并启用相应 API。

主要功能

  1. 01地理编码地址和坐标
  2. 02搜索地点并获取详情
  3. 03查询路线和距离矩阵
  4. 04查询天气、空气质量和花粉
  5. 05获取海拔、太阳能和道路数据
  6. 06生成静态地图和 Street View 图片

适用场景

  1. 01查找地点并查看详情
  2. 02规划路线并比较行程距离
  3. 03查询当地天气或环境状况
  4. 04验证地址并处理 GPS 轨迹

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tivojn/google-maps-api-skill --skill google-maps-api

安装后在 Claude Code 中输入/google-maps-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.env.example
.gitignore
README.md
.claude-plugin/
plugin.json
examples/
trip-plan-example.html
scripts/
gmaps.py

详细介绍

Google Maps Platform - 通用 API 技能

关键行为规则

这些规则优先于本技能中的所有其他指令:

  1. 立即说明遇到的阻碍。 任何 API 调用失败时(403、REQUEST_DENIED、“未启用”等),请立即停止,并用通俗的语言告诉用户发生了什么。不要默默改用网页搜索或其他备用方案。请提出通过 Playwright 修复问题(参见下方“引导式 API 启用”部分)。

  2. 生成 HTML 前先询问。 未经用户同意,绝不要开始编写 HTML 页面。他们可能只想要文本答复、JSON 输出或简要摘要。请询问:“要我为此制作一个交互式 HTML 页面,还是文本摘要就够了?”

  3. 选择输出格式前先询问。 当用户的请求可以用文本、JSON 或可视化页面来回答时,请询问他们偏好哪种格式。不要擅自决定。

概述

功能齐全的命令行客户端,支持 所有 Google Maps Platform REST API。与基于浏览器的 google-maps 技能不同,本技能直接调用 Google 的 API,以快速获取结构化 JSON 响应。涵盖地图、路线、地点、环境和地理空间服务领域的 20 多个 API。

设置

1. 获取 Google Maps API 密钥
  1. 前往 Google Cloud Console
  2. 创建或选择一个项目
  3. 启用所需的 API(请参见下方的 API 列表)
  4. 前往 API 和服务 > 凭据,然后创建 API 密钥
  5. (建议)将密钥限制为仅可用于所需的 API
2. 保存 API 密钥

将其添加到以下任一位置的 .env 文件中(按顺序搜索):

# Option 1: Project directory .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> .env

# Option 2: Home directory .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> ~/.env

# Option 3: Environment variable
export GOOGLE_MAPS_API_KEY=your_key_here
3. 启用所需的 API

在 Google Cloud Console > API 和服务 > 库中,启用所需的 API:

API 名称控制台名称
地理编码Geocoding API
路线Routes API
地点Places API (New)
海拔Elevation API
时区Time Zone API
空气质量Air Quality API
花粉Pollen API
太阳能Solar API
天气Weather API
地址验证Address Validation API
道路Roads API
街景Street View Static API
静态地图Maps Static API
地理定位Geolocation API
航拍视图Aerial View API
路线优化Route Optimization API
地点聚合Places Insights API

脚本位置

~/.claude/skills/google-maps-api/scripts/gmaps.py

无需外部依赖项——仅使用 Python 标准库(urllib、json、ssl)。

完整 API 参考

1. 地理编码

正向地理编码 - 将地址转换为坐标:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "1600 Amphitheatre Parkway, Mountain View, CA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Tokyo Tower" --language ja --region jp
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Paris" --components "country:FR"

反向地理编码 - 将坐标转换为地址:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 37.4224 -122.0856
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 48.8584 2.2945 --language fr
2. 路线和导航

获取两个地点之间的导航路线:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "New York, NY" "Boston, MA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "LAX" "SFO" --mode transit
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Seattle" "Portland" --alternatives --avoid-tolls
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "A" "D" --waypoints "B" "C"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Home" "Work" --mode bicycling --units imperial

距离矩阵 - 多个起点/目的地:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py distance-matrix \
  --origins "New York" "Boston" \
  --destinations "Philadelphia" "Washington DC"
3. 地点

文本搜索 - 根据查询查找地点:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "best pizza in Chicago"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "pharmacy" --location "40.714,-74.006" --radius 1000
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "5-star hotels" --min-rating 4.5 --open-now
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "EV charging" --type "electric_vehicle_charging_station"

附近搜索 - 查找坐标附近的地点:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 40.7128 -74.0060 --type restaurant --radius 800
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 34.0522 -118.2437 --type cafe --max-results 5

地点详情 - 获取地点的完整信息:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-details ChIJN1t_tDeuEmsRUsoyG83frY4

自动补全 - 输入时显示建议:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "star" --location "37.7749,-122.4194"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "central p" --types "park"

地点照片 - 获取照片 URL:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-photo "places/PLACE_ID/photos/PHOTO_REF" --max-width 800
4. 空气质量

当前状况:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060 --health --pollutants

历史数据(最多 30 天):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-history 40.7128 -74.0060 --hours 48

预测(最多 96 小时):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-forecast 40.7128 -74.0060
5. 花粉

花粉预测(最多 5 天,草类/杂草/树木):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 34.0522 -118.2437 --days 5

返回:3 种植物类型和 15 个物种的通用花粉指数(UPI)。

6. 太阳能

建筑太阳能潜力:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841 --quality HIGH

返回:屋顶面积、日照时长、最佳面板布局、能源/成本估算。

太阳能数据图层(DSM、通量、阴影栅格):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar-layers 37.4219 -122.0841 --radius 100
7. 天气

当前状况:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode current

每小时预测(最多 240 小时):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode hourly --hours 48

每日预测(最多 10 天):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode daily --days 7

近期历史(最多 24 小时):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode history --hours 12
8. 海拔
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation 39.7392 -104.9903
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --locations "39.7392,-104.9903|36.4555,-116.8666"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --path "36.578,-118.292|36.606,-118.099" --samples 20
9. 时区
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 35.6762 139.6503 --language ja
10. 地址验证
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "123 Main St" --region US --enable-usps

返回:可投递性判定、修正后的地址、组件级确认、USPS CASS 数据。

11. 道路

贴合道路 - 对齐 GPS 轨迹:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.171,-24.941|60.172,-24.940"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.172,-24.940" --interpolate

最近道路:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py nearest-roads "60.170,-24.942|60.171,-24.941"
12. 街景

CLI 数据使用(服务端下载图像,费用为每 1,000 次 $7):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --lat 46.414 --lng 10.013 --heading 90
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --location "Eiffel Tower, Paris" --size 800x600
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --pano CAoSLEFGMVFpcE... --output paris_sv.jpg

用于 HTML 页面——请始终改用 Google Maps 直接链接(零费用,不会暴露密钥):

https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch=0&fov=90

详情请参阅下方的“HTML 中的街景”部分。

**警告:**请勿使用旧的简写格式 @{lat},{lng},3a,75y,{heading}h,90t——它不可靠,通常会打开缩小后的世界地图,而不是街景。请始终使用上面的 map_action=pano 格式。

13. 静态地图
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --lat 40.714 --lng -74.006 --zoom 13
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "Tokyo" --maptype satellite --zoom 12
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "NYC" --markers "color:red|40.714,-74.006" --size 800x600
14. 地理定位
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation --wifi "00:11:22:33:44:55,-65" "66:77:88:99:AA:BB,-72"
15. 航拍视图(仅限美国)
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view check --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view render --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view get --video-id VIDEO_ID
16. 路线优化

求解车辆路径问题(VRP):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py route-optimize problem.json --project my-gcp-project

输入 JSON 格式:根据 Google Route Optimization API 规范,使用 {"model": {"shipments": [...], "vehicles": [...]}}。

17. 地点聚合(洞察)

统计或列出某个区域内符合筛选条件的地点:

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "40.714,-74.006" --radius 5000 --type restaurant
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "34.052,-118.244" --type cafe --min-rating 4.0 --insight INSIGHT_PLACES
18. Maps 嵌入网址(免费)

生成可嵌入的地图网址(免费且不限量):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode place --query "Eiffel Tower"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode directions --origin "NYC" --destination "Boston"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode streetview --lat 46.414 --lng 10.013

Claude 的使用模式

当用户询问位置、地理或环境问题时,请使用相应的命令:

用户意图命令
“……在哪里?”geocode
“……这个地址是什么?”reverse-geocode
“从 A 到 B 怎么走?”directions
“A 到 B 有多远?”distance-matrix
“查找附近的餐厅……”places-search 或 places-nearby
“……的营业时间是什么?”place-details
“……的空气质量怎么样?”air-quality
“今天花粉严重吗?”pollen
“……的天气怎么样?”weather
“这个地址有效吗?”validate-address
“……的海拔是多少?”elevation
“……属于哪个时区?”timezone
“给我看看……的地图”static-map
“我能在屋顶上安装太阳能板吗?”solar
“优化配送路线”route-optimize
“这个区域内有多少家咖啡店?”places-aggregate

交互式 HTML 输出

重要:生成 HTML 前务必先询问。 未经用户明确同意,绝不要开始编写 HTML 文件。以文本形式交付结果后,请询问:

“要我把这些内容整理成交互式 HTML 页面,方便你在浏览器中打开吗?默认主题为 Warm Stone Sunrise(浅色、暖色调、高级感)。”

如果用户同意(或明确要求生成 HTML、页面或地图),再生成。如果用户没有回应或表示拒绝,就只提供文本或 JSON 结果。

默认情况下,请使用 Google Maps 嵌入式 iframe(output=embed)生成无需密钥的 HTML 页面——无需 API 密钥,也没有密钥暴露风险。只有当用户明确要求嵌入式地图无法支持的高级交互功能(如自定义标记、折线、聚类等)时,才使用 Maps JavaScript API(<script src="https://maps.googleapis.com/maps/api/js?key=...">)。

零密钥嵌入式 iframe(默认)

地图请使用以下 iframe 格式——无需 API 密钥,且免费:

地点/位置地图:

<iframe src="https://maps.google.com/maps?q=Oahu+Hawaii&z=10&output=embed"
  width="100%" height="400" style="border:0" allowfullscreen></iframe>

路线地图:

<iframe src="https://maps.google.com/maps?saddr=Los+Angeles+CA&daddr=San+Jose+CA&output=embed"
  width="100%" height="400" style="border:0" allowfullscreen></iframe>

参数:

  • q — 地点名称或地址(URL 编码,空格用 + 表示)
  • saddr / daddr — 路线的起点/终点
  • z — 缩放级别(1-20,默认约为 12)
  • output=embed — 必填,使地图可嵌入
  • ll — 可选的中心坐标 lat,lng

警告: Google Maps 嵌入式 iframe 中请勿使用 loading="lazy"。延迟加载会阻止屏幕外的 iframe 加载,导致首屏下方的地图永久显示为空白。请始终省略 loading 属性,或使用 loading="eager"。

结果类型默认 HTML 元素
街景直接使用 Google Maps 链接(map_action=pano)——在新标签页中打开完整的交互式街景。请参阅“HTML 中的街景”部分。
路线使用带有 saddr / daddr 和 output=embed 的嵌入式 iframe
地点搜索使用带有 q=place+name 和 output=embed 的嵌入式 iframe,并附带信息卡片
附近搜索使用以地点为中心的嵌入式 iframe,并附带地点卡片
静态地图使用带有 q 和 z 的嵌入式 iframe(可缩放、可拖动)
天气/空气质量使用地点的嵌入式 iframe,并附带状况卡片、图标和图表
海拔海拔剖面图表 + 带有路径标记的嵌入式 iframe
太阳能使用建筑物位置的嵌入式 iframe,并附带太阳能潜力统计数据
行程规划组合式多区块页面:嵌入式 iframe 地图、地点卡片、天气组件

生成 HTML 页面时:

  1. 使用单个独立的 .html 文件(内联 CSS/JS,无外部依赖)
  2. 默认对所有地图使用零密钥嵌入式 iframe(output=embed)——HTML 中不得包含 API 密钥
  3. **HTML 页面中绝不可使用 google.maps.StreetViewPanorama 或街景 JS API。**街景始终使用带有 map_action=pano 的直接 Google Maps 链接。这是硬性规则。
  4. **除非用户明确要求高级交互功能,否则绝不可包含 Google Maps JS API <script> 标签。**使用 output=embed 的 iframe 方案即可满足大多数用例,无需任何 API 密钥。
  5. 使用描述性名称保存到当前工作目录(例如 marea-streetview.html、nyc-trip-plan.html)
  6. 创建完成后,通过 open <file>(macOS)自动在浏览器中打开
HTML 中的 Street View — 零密钥暴露

**硬性规则:绝不要在 HTML 页面中使用 JavaScript API 或 Embed API 嵌入 Street View。**这两种方式都会在客户端代码中暴露 API 密钥。应始终使用直接的 Google Maps 链接,在用户的浏览器中打开完整的交互式 Street View 体验——零成本,零 API 密钥暴露。

直接链接格式(Google Maps URLs API — 可靠):

https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch={pitch}&fov=90

参数:

  • viewpoint={lat},{lng} — Street View 位置的坐标
  • heading — 罗盘方向角度(0=北,90=东,180=南,270=西)
  • pitch — 俯仰角(-90=向下,0=水平,90=向上)
  • fov — 视野角度(10-100,默认值为 90)
  • map_action=pano — 必需 — 显式触发 Street View 全景模式

**警告:**不要使用旧的简写格式 @{lat},{lng},3a,75y,{heading}h,{pitch}t——它不可靠,经常无法打开 Street View,而是显示缩小的世界地图。始终使用 map_action=pano 格式。

示例:

https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.8584,2.2945&heading=180&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=46.414,10.013&heading=270&pitch=-5&fov=90

如何在 HTML 页面中实现:

独立的 Street View 按钮:

<a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90"
   target="_blank" rel="noopener noreferrer"
   style="display:inline-block; padding:12px 24px; background:#4f46e5; color:white;
          border-radius:8px; text-decoration:none; font-weight:600;">
  Open Street View →
</a>

JavaScript 函数(例如,用于包含多个地点的旅行计划页面):

function openStreetView(lat, lng, name) {
  window.open(
    `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${lat},${lng}&heading=0&pitch=0&fov=90`,
    '_blank'
  );
}

带有背景信息的卡片/预览:

<div class="streetview-card">
  <div class="sv-preview">
    
    <div class="sv-overlay">
      <span class="sv-icon">🔭</span>
      <span>Interactive Street View</span>
    </div>
  </div>
  <a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading=0&pitch=0&fov=90"
     target="_blank" rel="noopener noreferrer" class="sv-button">
    Open in Google Maps →
  </a>
  <p class="sv-note">Opens full 360° interactive Street View — pan, zoom, and walk around</p>
</div>

在整合后的旅行计划页面中,将原有的 StreetViewPanorama 部分替换为样式化的按钮/链接卡片。用户点击后即可在新标签页中打开完整的 Street View——直接通过 Google Maps 获得完整的交互式体验。

为何采用这种方式:

  • 零 API 密钥暴露——HTML 源代码中完全不包含密钥
  • 零成本——没有 API 调用,也不产生费用
  • 体验更佳——可使用带导航功能的完整 Google Maps Street View,而不是功能有限的嵌入内容
  • 适用于所有部署模式(个人、自带密钥、平台密钥)
一站式整合页面

对于包含多个部分的请求(旅行计划、地点调研、比较),始终主动提供生成一个整合后的 HTML 页面,将收集到的所有数据汇总到一个交互式仪表板中。用户应当能够一次查看所有内容,而不是滚动浏览终端输出。

整合页面应包含对话期间收集的每一项数据,例如,旅行计划页面可以整合:

  • 带有驾驶路线折线的交互式路线地图
  • 目的地天气组件
  • 带有照片、评分、营业时间的酒店/地点卡片
  • 附有 Street View 链接的餐厅推荐(可在 Google Maps 中打开完整的 360° 视图)
  • 时间线/行程安排部分
  • 租车与机场信息

整合页面的设计原则:

  • 使用简洁、现代的仪表板布局,并划分清晰的区块
  • 每个区块都应有丰富的视觉内容:地图、卡片、图标、徽章,而不只是文字
  • 包含平滑滚动导航(带有活动链接高亮的粘性磨砂玻璃导航栏)
  • 滚动显示动画(通过 IntersectionObserver 为每个区块实现向上淡入效果)
  • 完全响应式:桌面端(>1024px)、平板端(641-1024px)、移动端(<=640px)、小屏手机(<=380px)
  • 在移动端,卡片、按钮、旅行标签和统计网格改为单列布局
  • 在移动端缩小地图高度(280px),并让按钮占满宽度
默认主题:暖石日出

除非用户另有要求,否则所有 HTML 页面都默认使用此主题。

配色方案:

  • 背景:#fafaf9(暖调米白)
  • 表面:卡片使用 #ffffff,替代表面使用 #f5f5f4
  • 边框:#e7e5e4(暖石色),#f0eeec(浅色分隔线)
  • 文本:#1c1917(主要)、#57534e(次要)、#a8a29e(第三级)
  • 强调色:#4f46e5(靛蓝),搭配浅色 #eef2ff 和中间色 #c7d2fe
  • 语义色:绿色 #059669、琥珀色 #d97706、红色 #dc2626、蓝色 #2563eb

排版:

  • 标题:Playfair Display(衬线字体,字重 700-900)——营造精致的编辑风格
  • 正文:Inter(无衬线字体),启用完整字体平滑
  • 区块模式:大写标签(11px,强调色)→ 衬线标题(26px)→ 描述(14px,第三级)

主视觉: linear-gradient(160deg, #eef2ff, #faf5ff, #fff7ed)——从靛蓝过渡到薰衣草色,再到蜜桃色

地图: 默认通过嵌入式 iframe 使用 Google Maps 样式。选择使用 Maps JS API 时,应用浅色自定义样式——柔和的石色调、淡蓝色水域 #c9d7e4、绿色公园 #d4e9d4、白色道路

阴影: 基础阴影柔和,为 0 1px 2px rgba(0,0,0,0.04);悬停时使用 0 4px 6px

导航: 粘性磨砂玻璃效果(rgba(255,255,255,0.85) + backdrop-filter: blur(20px)),活动链接带下划线动画

交互: 卡片悬停时上移(translateY(-2px))、时间轴圆点填充并带光环、步骤悬停时缩进、按钮悬停时上移并增强阴影

API 密钥安全与生产架构

问题

嵌入客户端 HTML/JavaScript 的任何 API 密钥都可由用户通过浏览器开发者工具查看。这对于个人使用没有问题,但对于服务多个用户的生产应用来说,至关重要。

部署模式

此技能支持三种安全级别不同的部署模式:

模式 1:个人 / CLI 使用(单用户)

用户自己的 API 密钥存放在 .env 中,由 gmaps.py 在本地使用。密钥不会离开本机。

User's Machine
├─ .env (GOOGLE_MAPS_API_KEY=...)
├─ gmaps.py → calls Google APIs directly
└─ HTML pages → zero-key embed iframes (preferred) or key embedded (acceptable)

风险:低——这是用户自己的密钥,存放在自己的机器上。 密钥限制:无需设置(也可以限制为你所用的 API)。 最佳实践:即使是个人使用,HTML 页面也应优先使用零密钥的 output=embed iframe。只有在需要高级功能(自定义标记、折线、聚类)时,才使用 Maps JS API。

模式 2:用户自带密钥(多用户应用)

用户配置自己的 Google API 密钥,并自行承担费用。

Your App
├─ User configures their own API key in app settings
├─ Key stored in user's profile (encrypted at rest)
├─ Used server-side for data queries
└─ Frontend key: user creates a separate domain-restricted key

风险:低至中等——这是用户自己的密钥,由用户承担费用。 重要:生成可分享 / 导出的 HTML 页面时,绝不要嵌入用户的密钥。应改用静态导出(参见下文的“可分享导出模式”)。 引导流程:指导用户完成 GCP Console 设置和 API 启用(参见上文“设置”部分)。

模式 3:平台密钥(用户向你付费)——至关重要

用户向你的平台付费。由你提供 Google API 密钥。用户绝不能看到该密钥。

架构:双密钥 + 后端代理

┌─────────────────────────────────────────────────────┐
│  User's Browser                                      │
│                                                       │
│  HTML Page (served from app.yourdomain.com)           │
│  ├─ Interactive Maps  ← Frontend Key (domain-locked)  │
│  ├─ Street View       ← Frontend Key (domain-locked)  │
│  └─ All data (weather, places, directions, etc.)      │
│       ↑ pre-rendered from backend, NO key in browser  │
│                                                       │
└──────────────────┬────────────────────────────────────┘
                   │ /api/geocode, /api/directions, etc.
                   ▼
┌──────────────────────────────────────────────────────┐
│  YOUR Backend Server                                  │
│                                                       │
│  Backend Key (env var, never sent to browser)         │
│  ├─ Geocoding, Directions, Places, Weather, etc.      │
│  ├─ Street View Static → returns image bytes          │
│  └─ All data APIs proxied with your key server-side   │
│                                                       │
│  Key restricted by: Server IP address                 │
│  Even if leaked: won't work from other IPs            │
└──────────────────┬────────────────────────────────────┘
                   │
                   ▼
            Google Maps Platform

前端密钥(客户端,在 HTML 中):

  • 仅启用:Maps JavaScript API(用于交互式地图渲染)
  • 限制方式:HTTP 引用来源 → https://app.yourdomain.com/*
  • 即使有人复制该密钥,也只能从你的域名使用
  • 无法调用数据 API(地理编码、地点等)——这些 API 在此密钥上已禁用

后端密钥(服务器端,隐藏):

  • 启用:所有数据 API(地理编码、路线、地点、天气、花粉、太阳能等)
  • 限制方式:服务器 IP 地址
  • 永远不会发送到浏览器——仅保存在服务器环境变量中
  • 即使泄露,也只能通过服务器的 IP 使用

此模式下 HTML 页面的工作方式:

// UNSAFE — key exposed, data fetched client-side:
const service = new google.maps.DirectionsService();
service.route({ origin: 'JFK', destination: 'The Plaza' });

// SAFE — data pre-fetched by backend, only map rendering in browser:
const routeData = /* injected by server from backend API call */;
const path = google.maps.geometry.encoding.decodePath(routeData.polyline);
new google.maps.Polyline({ path: path, map: map });
在 GCP Console 中设置两个密钥
步骤 1:创建前端密钥
  1. 在 GCP Console 中前往 APIs & Services > Credentials
  2. 点击 Create Credentials > API Key
  3. 点击该密钥进行编辑
  4. 在 Application restrictions 下:选择 HTTP referrers
  5. 添加你的域名:https://app.yourdomain.com/*
  6. 在 API restrictions 下:选择 Restrict key
  7. 仅启用:Maps JavaScript API
  8. 保存
步骤 2:创建后端密钥
  1. 再次点击 Create Credentials > API Key
  2. 点击该密钥进行编辑
  3. 在 Application restrictions 下:选择 IP addresses
  4. 添加你的服务器 IP 地址
  5. 在 API restrictions 下:选择 Restrict key
  6. 启用:Geocoding、Routes、Places (New)、Weather、Air Quality、Pollen、Solar、Elevation、Time Zone、Address Validation、Roads、Street View Static、Geolocation、Aerial View、Route Optimization
  7. 保存
步骤 3:配置你的应用
# Backend server environment
GOOGLE_MAPS_BACKEND_KEY=AIzaSy...xxx   # Server-side only, IP-restricted
GOOGLE_MAPS_FRONTEND_KEY=AIzaSy...yyy  # Injected into HTML, domain-restricted
可分享导出模式

当用户想要下载或分享 HTML 页面(电子邮件、Slack 等)时,生成不含任何 API 密钥的静态导出:

元素应用内(交互式)可分享导出
地图Maps JavaScript API(前端密钥)Maps Embed API <iframe>(免费,没有密钥滥用风险)
街景直接使用 Google Maps 链接(不需要密钥)直接使用 Google Maps 链接(不需要密钥)
路线DirectionsRenderer(前端密钥)带有路径叠加层的静态地图图像(base64)
数据(天气、地点)从后端预先渲染相同的预渲染 HTML——不需要 API 调用
API 密钥暴露前端密钥,受域名限制完全没有密钥

生成嵌入 URL(免费、无限制):

python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode place --query "Marea Restaurant NYC"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode directions --origin "JFK" --destination "The Plaza Hotel NYC"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode streetview --lat 40.76545 --lng -73.98115
安全摘要
部署方式数据 API地图渲染密钥暴露可分享
个人 CLI用户的密钥,位于本地零密钥嵌入式 iframe(默认)无是(无密钥)
个人 CLI(高级)用户的密钥,位于本地Maps JS API(选择启用折线、聚类等)用户自行承担风险否(密钥会泄露)
BYOK(用户的密钥)用户的密钥,位于服务器上用户创建前端密钥用户自行承担风险仅静态导出
平台密钥(由你付费)后端密钥(锁定 IP)前端密钥(锁定域名)安全仅静态导出
速率限制与滥用防护(平台模式)

使用你的密钥为多个用户提供服务时,还应实施以下措施:

  • 按用户进行速率限制:限制每位用户每小时/每天的 API 调用次数
  • 身份验证:只有经过身份验证且付费的用户才能触发 API 调用
  • 用量跟踪:记录触发各 API 调用的用户,以便计费
  • 配额提醒:设置 GCP 账单提醒,以便发现意外峰值
  • 预算上限:在 GCP Console 中设置每日最高支出

错误处理与 API 设置引导

重要:任何命令失败时,必须立即告知用户。 不要悄悄改用网页搜索或其他变通方案。用户需要知道哪里出了问题,才能决定如何修复。

命令失败时,检测错误类型并作出相应响应:

  • 403 Forbidden / API 未启用:停止。告知用户,并提供 Playwright 引导操作(见下文)
  • REQUEST_DENIED:停止。告知用户,并提供 Playwright 引导操作(见下文)
  • 400 Bad Request:参数无效——检查 API 文档
  • 429 Rate Limited:请求过多——加入短暂延迟
  • ZERO_RESULTS:未找到结果——尝试扩大搜索范围
  • INVALID_REQUEST:缺少必需参数
  • 未找到密钥:确保已在 .env 或环境变量中设置 GOOGLE_MAPS_API_KEY
  • RefererNotAllowedMapError:前端密钥的 HTTP 引荐来源限制与当前域名不匹配
引导式 API 启用(Playwright 演示)

当 API 尚未启用时,这是首选响应。 不要跳过,也不要悄悄绕过此问题。

当用户的 API 调用因 403、REQUEST_DENIED 或“API 尚未启用”错误而失败时:

  1. 用通俗的语言告诉用户发生了什么:

    "看起来您的 Google Cloud 项目尚未启用 [API Name]。没关系——我可以现在就在您的浏览器中引导您完成启用。要我继续吗?"

  2. 如果用户同意,使用 Playwright MCP 自动完成启用:

    Step 1: Navigate to the specific API's enablement page:
            https://console.cloud.google.com/apis/library/[API_ENDPOINT]
    
    Step 2: If a project selector appears, let the user pick their project
            (or auto-select if there's only one)
    
    Step 3: Click the "Enable" button
    
    Step 4: Wait for the confirmation (loading spinner → "API enabled" or
            the button changes to "Manage")
    
    Step 5: Confirm to the user: "Done! [API Name] is now enabled.
            Let me retry your request."
    
    Step 6: Retry the original command automatically
    
  3. Playwright 导航所用的 API 端点 URL(使用以下确切路径):

    APIGCP Library URL 路径
    Geocodinggeocoding-backend.googleapis.com
    Routesroutes-backend.googleapis.com
    Places (New)places-backend.googleapis.com
    Elevationelevation-backend.googleapis.com
    Time Zonetimezone-backend.googleapis.com
    Air Qualityairquality.googleapis.com
    Pollenpollen.googleapis.com
    Solarsolar.googleapis.com
    Weatherweather.googleapis.com
    Address Validationaddressvalidation.googleapis.com
    Roadsroads.googleapis.com
    Street View Staticstreet-view-image-backend.googleapis.com
    Maps Staticstatic-maps-backend.googleapis.com
    Maps JavaScriptmaps-backend.googleapis.com
    Maps Embedmaps-embed-backend.googleapis.com
    Geolocationgeolocation.googleapis.com
    Aerial Viewaerialview.googleapis.com
    Route Optimizationrouteoptimization.googleapis.com

    URL 完整格式:https://console.cloud.google.com/apis/library/[path_from_table]

  4. 如果用户拒绝(希望手动操作),请提供直接链接:

    "没问题!这是直接链接——点击 Enable 即可: https://console.cloud.google.com/apis/library/[API_ENDPOINT]"

  5. 批量启用:如果用户是首次设置,且需要启用多个 API,请主动提出一次性全部启用:

    "我可以一次性为您启用所有常用 API:Geocoding、Routes、Places、Weather、Elevation、Time Zone 和 Maps JavaScript。要我帮您全部设置好吗?"

    然后通过 Playwright 逐个访问各 API 页面,并点击 Enable。

  6. Playwright 演示的重要说明:

    • 用户必须已在浏览器中登录 Google Cloud Console
    • 如果尚未登录,请告知他们先访问 https://console.cloud.google.com 登录
    • 某些 API(Weather、Solar)可能要求项目启用结算功能
    • 启用后可能需要约 30 秒才能生效
    • 如果看不到 Enable 按钮,而是显示 Manage,则说明该 API 已启用

定价说明

大多数 API 按请求收费。主要免费/付费档位:

  • Maps Embed API:始终免费(可用于生成可分享的导出内容)
  • Maps JavaScript API:每 1,000 次加载收费 $7
  • Street View (JS):每 1,000 次全景加载收费 $7——绝不要在 HTML 页面中使用;请改用直接的 Google Maps 链接(免费,无需密钥)
  • Google Maps Platform 每月提供 $200 免费额度
  • Routes API:每 1,000 次请求收费 $5-15,具体取决于功能
  • Places API:每 1,000 次请求收费 $17-40
  • Environment API(Air Quality、Pollen、Solar):价格不一
  • 请查看 Google Maps 定价了解当前费率

说明

  • 所有输出均为 JSON(图片下载除外,图片会保存为文件)
  • 无需外部 Python 依赖——仅使用标准库
  • 脚本会在以下位置查找 .env:CWD、主目录、skill 目录
  • 对于图片 API(streetview、static-map),文件会保存在本地
  • Weather API 可能需要单独启用结算功能
  • Aerial View 仅支持美国地址
  • Route Optimization 需要 GCP 项目 ID
  • Roads 的限速功能需要 Asset Tracking 许可证

评论

支持 Markdown