Geocoding API v4 引入了多种新方法,可替代 API v3 中的功能。本指南将介绍如何迁移应用以使用新的 v4 方法。
您可以将现有 API 密钥与新的 v4 方法搭配使用。不过,如果您已针对 API 的 v3 版本请求提高配额,则必须针对新的 v4 API 请求提高配额。
从 v3 正向地理编码迁移
如果您使用 v3 地理编码对地址进行地理编码,则应迁移到接受 GET 请求的 v4 对地址进行地理编码方法。
v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定您希望在响应中返回的字段。
请求参数变更
| v3 参数 | v4 参数 | 备注 |
|---|---|---|
address、components |
address |
非结构化地址 (v3 address) 现在通过网址路径传递。结构化地址组成部分 (v3 components) 可以作为 address.* 查询参数传递。请参阅重现 v3 组件过滤条件。 |
bounds |
locationBias.rectangle |
已重命名;结构已更改为对象。 |
language |
languageCode |
已重命名。 |
region |
regionCode |
已重命名。 |
extra_computations |
已移除 | 已替换为 SearchDestinations 方法。 |
响应字段变更
| v3 字段 | v4 字段 | 备注 |
|---|---|---|
status、error_message |
已移除 | v4 使用 HTTP 状态代码和错误正文。 |
results.address_components.long_name/results.address_components.short_name |
results.addressComponents.longText/results.addressComponents.shortText |
已重命名。 |
results.geometry.location_type |
results.granularity |
已重命名。 |
results.geometry.location |
results.location |
字段名称:lat/lng -> latitude/longitude。 |
results.geometry.viewport |
results.viewport |
字段名称:northeast/southwest -> high/low。 |
results.postcode_localities |
results.postalCodeLocalities |
已重命名。现在,针对一个或多个地区返回(需要 v3 >1)。 |
results.partial_match |
已移除 | |
| 全新设计 | results.addressComponents.languageCode |
特定地址组成部分的语言。 |
| 全新设计 | results.bounds |
使用 high/low 设置明确的边界。 |
| 全新设计 | results.place |
地点的资源名称。 |
| 全新设计 | results.postalAddress |
结构化 PostalAddress 对象。 |
重现 v3 组件过滤器
地理编码 v3 中的正向地理编码包含一个 components 参数,可用于对特定组件(例如 components=country:US)的结果进行硬过滤。v4 中的正向地理编码不支持在请求参数中进行此类硬过滤。在 v4 中,您可以提供地址信息,既可以采用路径中的单个非结构化字符串,也可以采用结构化查询参数,例如 address.addressLines、address.locality、address.administrativeArea、address.postalCode 和 address.regionCode。
结构化参数不会充当硬过滤条件。相反,系统会将所有提供的组成部分组合起来,形成 API 将尝试进行地理编码的完整地址。该 API 会在所有组件中搜索与指定完整地址最匹配的结果。以结构化方式提供组件有助于 API 更好地理解意图,尤其是在从单独的表单字段收集地址信息时。由于每个字段中的信息类型都很明确,因此这有助于 API 处理每个组件中的细微拼写错误或歧义。
若要实现与 v3 的硬性组件过滤条件类似的行为,您必须根据响应中的 postalAddress 和 addressComponents 对象,对 v4 API 返回的 results 数组实现客户端过滤。
下表显示了 v3 components 过滤条件与 v4 postalAddress 字段之间的最佳匹配:
| v3 组件过滤条件 | v4 响应字段 |
|---|---|
country |
postalAddress.regionCode |
postal_code |
postalAddress.postalCode |
administrative_area |
postalAddress.administrativeArea 或 addressComponents |
客户端过滤示例
以下示例展示了如何过滤结果,以实现与 v3 组件过滤类似的行为(针对受支持的字段:国家/地区、行政区和邮政编码)。不建议按其他字段进行过滤,因为没有可靠的过滤条件。
按国家/地区过滤
将请求中的 address.regionCode 与每个结果中的 postalAddress.regionCode 进行匹配。请注意,虽然 API 接受请求中的小写区域代码,但始终会在响应中返回大写区域代码,因此您必须先将输入内容标准化为大写,然后再进行比较。
Python 代码示例
def filter_by_country(results, region_code): return [ res for res in results if res.get('postalAddress', {}).get('regionCode') == region_code.upper() ] # Example usage: # v4_response = ... # API call response # filtered = filter_by_country(v4_response.get('results', []), 'US')
Node.js 代码示例
function filterByCountry(results, regionCode) { return results.filter(res => res.postalAddress?.regionCode === regionCode.toUpperCase()); } // Example usage: // const v4Response = ... # API call response // const filtered = filterByCountry(v4Response.results, 'US');
按行政区过滤
将请求中的 address.administrativeArea 与每个结果中的 postalAddress.administrativeArea 进行匹配。与国家/地区代码类似,您应先将输入内容标准化为大写,然后再进行比较。只有当请求中的 administrativeArea 采用标准的双字母缩写形式时,此方法才可靠。出于多种原因,响应中的 postalAddress.administrativeArea 可能不会直接与 ISO 3166-2 代码后缀匹配。首先,在某些地区,与 ISO 3166-2 代码对应的细分区域不属于邮政地址的标准表示形式。例如,在西班牙,addressComponents 中可能包含行政区域级别 1(例如,加那利群岛的“CN”),但 postalAddress.administrativeArea 可能包含级别 2 的区域(例如,“圣克鲁斯-德特内里费”)。其次,在某些地区,细分的缩写并不常用,而是以较长的名称表示(出于类似原因,与细分对应的地址组成部分的 addressComponents.shortText 可能与细分的 ISO 3166-2 代码后缀不匹配)。postalAddress.administrativeArea此外,在某些情况下,细分可能在 administrative_area_level_n 的地址组成部分中表示,其中 n 大于 1。
为了获得最全面的结果,您应该检查 postalAddress.administrativeArea 和任何具有 administrative_area_level_n 类型(例如 administrative_area_level_1)的 addressComponents 中是否存在匹配项。
Python 代码示例
def filter_by_admin_area(results, admin_area): target = admin_area.upper() filtered = [] for res in results: # Check postalAddress pa_aa = res.get('postalAddress', {}).get('administrativeArea', '') if pa_aa == target: filtered.append(res) continue # Check all administrative area levels in addressComponents for comp in res.get('addressComponents', []): is_admin_level = any(t.startswith('administrative_area_level_') for t in comp.get('types', [])) if is_admin_level: short = comp.get('shortText', '') if short == target: filtered.append(res) break return filtered # Example usage: # filtered = filter_by_admin_area(v4_response.get('results', []), 'CA')
Node.js 代码示例
function filterByAdminArea(results, adminArea) { const target = adminArea.toUpperCase(); return results.filter(res => { // Check postalAddress.administrativeArea if (res.postalAddress?.administrativeArea === target) { return true; } // Check addressComponents for any administrative area level return res.addressComponents?.some(c => { const isAdmin = c.types?.some(t => t.startsWith('administrative_area_level_')); return isAdmin && c.shortText === target; }); }); } // Example usage: // const filtered = filterByAdminArea(v4Response.results, 'CA');
按邮政编码过滤
将请求中的 address.postalCode 与每个结果中的 postalAddress.postalCode 进行匹配。您必须先对输入邮政编码和结果邮政编码进行归一化,然后再进行比较。归一化逻辑在很大程度上取决于区域。一种基本方法是移除空格和连字符,并将字母转换为一致的大小写。
可能需要更高级别的规范化来处理邮政编码前缀(例如英国的“L2”)或后缀(例如美国邮政编码中的“+4”)。所需的具体规范化逻辑因国家/地区和所涉及的邮政编码格式而异。您可能需要调整提供的标准化函数,或针对目标区域实现更复杂的逻辑。
提供的示例可处理美国邮政编码,即使提供或返回的是 ZIP+4,也允许匹配 5 位数的基本邮政编码。
Python 代码示例(以美国邮政编码为重点)
import re def normalize_postal_code_us(pc): # Basic normalization for US: uppercase, alphanumeric only if not pc: return "" normalized = re.sub(r'[^A-Z0-9]', '', pc.upper()) # Return only the first 5 digits for US ZIP codes return normalized[:5] def filter_by_postal_code_us(results, postal_code): normalized_input = normalize_postal_code_us(postal_code) if not normalized_input: return [] filtered_results = [] for res in results: pa_pc = res.get('postalAddress', {}).get('postalCode', '') if normalize_postal_code_us(pa_pc) == normalized_input: filtered_results.append(res) return filtered_results # Example usage: # Matches '94043', '94043-1351', '940431351' # filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043') # filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043-1234')
Node.js 代码示例(以美国邮政编码为重点)
function normalizePostalCodeUs(pc) { // Basic normalization for US: uppercase, alphanumeric only const normalized = (pc || '').toUpperCase().replace(/[^A-Z0-9]/g, ''); // Return only the first 5 digits for US ZIP codes return normalized.substring(0, 5); } function filterByPostalCodeUs(results, postalCode) { const normalizedInput = normalizePostalCodeUs(postalCode); if (!normalizedInput) { return []; } return results.filter(res => { const paPc = res.postalAddress?.postalCode || ''; return normalizePostalCodeUs(paPc) === normalizedInput; }); } // Example usage: // Matches '94043', '94043-1351', '940431351' // const filtered = filterByPostalCodeUs(v4Response.results, '94043'); // const filtered = filterByPostalCodeUs(v4Response.results, '94043-1234');
从 v3 反向地理编码迁移
如果您使用 v3 反向地理编码将坐标转换为地址,则应迁移到接受 GET 请求的 v4 对位置进行反向地理编码方法。
v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定您希望在响应中返回的字段。
请求参数变更
| v3 参数 | v4 参数 | 备注 |
|---|---|---|
language |
languageCode |
已重命名。 |
region |
regionCode |
已重命名。 |
result_type |
types |
已重命名;使用重复的查询参数。 |
location_type |
granularity |
已重命名;使用重复的查询参数。 |
extra_computations |
已移除 | 已替换为 SearchDestinations 方法。 |
响应字段变更
| v3 字段 | v4 字段 | 备注 |
|---|---|---|
status、error_message |
已移除 | v4 使用 HTTP 状态代码和错误正文。 |
results.address_components.long_name/results.address_components.short_name |
results.addressComponents.longText/results.addressComponents.shortText |
已重命名。 |
results.geometry.location_type |
results.granularity |
已重命名。 |
results.geometry.location |
results.location |
字段名称:lat/lng -> latitude/longitude。 |
results.geometry.viewport |
results.viewport |
字段名称:northeast/southwest -> high/low。 |
| 全新设计 | results.addressComponents.languageCode |
特定地址组成部分的语言。 |
| 全新设计 | results.bounds |
使用 high/low 设置明确的边界。 |
| 全新设计 | results.place |
地点的资源名称。 |
| 全新设计 | results.postalAddress |
结构化 PostalAddress 对象。 |
从 v3 地址描述符迁移
如果您使用 address_descriptor 通过 Geocoding v3 获取有关位置的其他信息,则必须迁移到使用 SearchDestinationsResponse 的 landmarks 字段。
从 v3 Place 地理编码迁移
如果您使用 place_id 通过 Geocoding v3 获取特定地点 ID 的地址,则必须迁移到 v4 Place Geocoding 方法,该方法接受 GET 请求。
v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定您希望在响应中返回的字段。
请求参数变更
| v3 参数 | v4 参数 | 备注 |
|---|---|---|
place_id |
请求 proto 中的 place 字段 |
地点 ID 现在以路径参数 places/{place} 的形式提供,例如:https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw。这会映射到底层请求中的地点字段。 |
language |
languageCode |
已重命名。 |
region |
regionCode |
已重命名。 |
响应字段变更
| v3 字段 | v4 字段 | 备注 |
|---|---|---|
status、error_message |
已移除 | v4 使用 HTTP 状态代码和错误正文。 |
results |
(根) | v4 返回单个结果对象,而不是 results 数组。 |
results.address_components.long_name/results.address_components.short_name |
addressComponents.longText/addressComponents.shortText |
已重命名。 |
results.geometry.location_type |
granularity |
已重命名。 |
results.geometry.location |
location |
字段名称:lat/lng -> latitude/longitude。 |
results.geometry.viewport |
viewport |
字段名称:northeast/southwest -> high/low。 |
results.postcode_localities |
postalCodeLocalities |
已重命名。现在,针对一个或多个地区返回(需要 v3 >1)。 |
| 全新设计 | addressComponents.languageCode |
特定地址组成部分的语言。 |
| 全新设计 | bounds |
使用 high/low 设置明确的边界。 |
| 全新设计 | place |
地点的资源名称。 |
| 全新设计 | postalAddress |
结构化 PostalAddress 对象。 |
从地理编码超本地数据迁移到目的地
Geocoding API v3 中的以下功能将由 Geocoding API v4 的 SearchDestinations 方法取代:
- 进入次数
- 导航点
- 构建轮廓
- 场地
如果您之前使用 Geocoding API v3 来实现上述功能,请参阅本文档,了解如何改用 SearchDestinations 方法来实现这些功能。本文档介绍了在 SearchDestinations 响应中可在何处找到这些功能,以及 Geocoding API v3 与 Geocoding API v4 的 SearchDestinations 方法在 API 响应中表示这些功能的方式有何不同。
进入次数
如需获取与 destination 关联的入口,请使用字段 destination.entrances。
请注意,entrance 的格式与 Geocoding API v3 中的入口格式略有不同。destination.entrances 中的每个入口都包含以下字段:
displayName- 这是一个新的可选字段,其中将包含入口的直观易懂的名称,例如“B 门”。location- 这是LatLng类型的地理位置,与 Geocoding API v3 中使用的格式不同。tags- 这与 Geocoding API v3 中入口的tags字段相同。place- 类似于 Geocoding API v3 中入口的buildingPlaceId字段。不过,此字段中的地点 ID 可以是任何类型的地点,不一定只是建筑物。
导航点
如需获取与 destination 关联的导航点,请使用字段 destination.navigationPoints。
请注意,navigationPoint 的格式与 Geocoding API v3 中的导航点格式略有不同。destination.navigationPoints 中的每个导航点都包含以下字段:
displayName- 这是一个新的可选字段,其中将包含导航点的直观易懂的名称,例如“第五大道”。location- 这是LatLng类型的地理位置,与 Geocoding API v3 中使用的格式不同。travelModes- 这类似于 Geocoding API v3 中导航点的restrictedTravelModes字段。可能的枚举值相同,唯一的区别是,此字段现在表示导航点的可接受出行模式,而不是受限出行模式。usage- 这是一个新字段,包含导航点支持的用例。请注意,大多数导航点都会有UNKNOWN用法,但这并不一定意味着导航点的用法受到任何限制。
构建轮廓
如需获取与 destination 关联的建筑物轮廓,您应使用 destination 中表示建筑物的 placeView 对象的 displayPolygon 字段。对于每个 placeView,您可以使用 placeView.structureType 字段检查它是否为建筑物。如果结构类型为 BUILDING,您可以从 placeView.displayPolygon 字段获取轮廓。placeView 还将包含 Geocoding API v3 中没有的建筑物的其他字段。
destination 可以通过以下字段包含表示建筑物的 placeView 对象:
destination.primary- 这是目标的主要位置。destination.containingPlaces- 这是重复字段,可包含“包含”主要地点的较大地点。例如,如果主要地点是subpremise,containingPlaces通常会保存表示相应建筑物的placeView。destination.subDestinations- 这是重复字段,可包含主要地点的子目的地。例如,建筑物的各个公寓单元。此字段通常不会包含表示建筑物的placeView。
请注意,placeView.displayPolygon 的格式与 Geocoding API v3 中的建筑轮廓格式(即 GeoJSON 格式,使用 RFC 7946 格式)相匹配。
场地
与构建轮廓类似,如需获取与 destination 关联的地面,您应使用 destination 中表示地面的 placeView 对象的 displayPolygon 字段。对于每个 placeView,您可以使用 placeView.structureType 字段检查它是否为理由。如果结构类型为 GROUNDS,您可以从 placeView.displayPolygon 字段获取轮廓。placeView 还将包含 Geocoding API v3 中没有的其他字段(用于表示理由)。
destination 可以包含一个 placeView 对象,该对象表示以下字段中的理由:
destination.primarydestination.containingPlacesdestination.subDestinations
请注意,placeView.displayPolygon 的格式与 Geocoding API v3 中的场地轮廓格式(即 GeoJSON 格式,使用 RFC 7946 格式)相匹配。
结果的精确度
在 Geocoding API v3 中,响应几何图形中的 location_type 字段表示结果的精确度,某些客户端会根据这些值(ROOFTOP、RANGE_INTERPOLATED、GEOMETRIC_CENTER 和 APPROXIMATE)对结果进行排名或过滤。在标准 Geocoding API v4 迁移中,此字段已重命名为 granularity。
在 Destinations API (v4 SearchDestinations) 中,没有 location_type 字段。不过,空间信息的处理方式有所不同:
- 无需手动进行客户端过滤:虽然标准地理编码会提供不同粒度的多个结果,但
SearchDestinations方法会尽可能解析为单个优化后的目的地,从而最大限度地减少歧义。这样一来,客户就不需要按位置类型进行过滤,即可确定哪个结果是最佳结果。 - 由结构类型和显示多边形表示的空间信息:空间几何图形和结构通过以下方式指示:
displayPolygon(用于精确几何图形)。placeView对象中的structureType字段。
- 结构类型映射:
- 值为
POINT、BUILDING或SECTION的structureType通常对应于之前称为ROOFTOP的内容。 GROUNDS的structureType通常对应于GEOMETRIC_CENTER。
- 值为
使用字段掩码请求这些功能
SearchDestinations 方法需要一个字段掩码,如选择要返回的字段中所述。您可以将字段掩码设置为 * 以返回所有字段,也可以将其设置为您要接收的特定字段。例如,以下 API 请求设置了字段掩码,以接收获取目的地入口、导航点、建筑物轮廓和地面所需的所有字段:
curl -X POST -d '{"place": "places/ChIJG3kh4hq6j4AR_XuFQnV0_t8"}' \
-H "X-Goog-Api-Key: API_KEY" \
-H "Content-Type: application/json" \
-H "X-Goog-FieldMask: destinations.entrances,destinations.navigationPoints,destinations.primary,destinations.containingPlaces,destinations.subDestinations" \
https://geocode.googleapis.com/v4/geocode/destinations
安全注意事项
Geocoding API v4 旨在作为服务器到服务器的 API。JavaScript 用户无法直接从 v3 迁移到 v4。直接从客户端 JavaScript(例如在浏览器中)使用 API 密钥调用 v4 方法会使您的 API 密钥面临被盗用和滥用的高风险。
HTTP Referer 限制虽然有用,但对于 Web 服务端点来说,保护力度不够,因为攻击者可以通过在请求中伪造 Referer 标头来轻松绕过这些限制。
建议的方法
建议您通过自己的后端服务器使用 Geocoding API v4。您的客户端应用应向此中介服务器发出请求,然后该服务器使用受保护的 API 密钥(例如存储在环境变量或 Secret 管理器中的密钥)安全地调用 Google API。这样可确保您的 API 密钥永远不会在前端代码中公开。
满足客户端需求的替代方案
如果您有需要地理编码的客户端需求,请考虑使用以下现有客户端解决方案之一:
- Maps JavaScript API 中的地理编码服务:地理编码服务继续使用 v3 后端,专为在浏览器环境中使用而设计。
- Places UI Kit:使用 Places UI Kit(包括地点自动补全元素)来创建与地址相关的界面元素。