从地理编码 v3 迁移到 v4

欧洲经济区 (EEA) 开发者

Geocoding API v4 引入了多个新方法,用于取代该 API v3 中的功能。本指南介绍了如何迁移应用以使用新的 v4 方法。

您可以将现有 API 密钥与新的 v4 方法搭配使用。不过,如果您已申请提高 v3 版 API 的配额,则必须申请提高新版 v4 API 的配额。

从 v3 正向地理编码迁移

如果您使用 v3 地理编码对地址进行地理编码,则应迁移到 v4 对地址进行地理编码方法,该方法接受 GET 请求。

v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定要在响应中返回的字段。

请求参数更改

v3 参数 v4 参数 备注
address、components address 非结构化地址 (v3 address) 现在通过网址路径传递。结构化地址组成部分 (v3 components) 可以作为 address.* 查询参数传递。请参阅重现 v3 组件过滤条件。
bounds locationBias.rectangle 已重命名;结构已更改为对象。
language languageCode 已重命名。如果省略此参数,v3 会使用 Accept-Language 标头或默认为 en,而 v4 会默认为相应位置的本地语言和文字。
region regionCode 已重命名。如果省略,v3 默认为 us,而 v4 没有默认值。
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 采用标准的 2 字母缩写时,此功能才可靠。响应中的 postalAddress.administrativeArea 可能不会直接与 ISO 3166-2 代码后缀匹配,原因有很多。首先,在某些地区,与 ISO 3166-2 代码对应的细分代码不属于邮政地址的标准表示形式。例如,在西班牙,行政区域级别 1(例如,加那利群岛的“CN”)可能存在于 addressComponents 中,但 postalAddress.administrativeArea 可能包含级别 2 的区域(例如,“圣克鲁斯德特内里费”)。其次,在某些地区,行政区划的缩写并不常用,在 postalAddress.administrativeArea 中会以较长的名称表示(出于类似原因,与行政区划对应的地址组成部分的 addressComponents.shortText 可能与行政区划的 ISO 3166-2 代码后缀不匹配)。此外,在某些情况下,细分行政区可能会在 administrative_area_level_n 的地址组成部分中表示,其中 n 大于 1。 为了获得最全面的结果,您应该同时检查 postalAddress.administrativeArea 和任何 administrative_area_level_n 类型为 addressComponents(例如 administrative_area_level_1)的匹配项。

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 反向地理编码将坐标转换为地址,则应迁移到 v4 对位置进行反向地理编码方法,该方法接受 GET 请求。

v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定要在响应中返回的字段。

请求参数更改

v3 参数 v4 参数 备注
language languageCode 已重命名。如果省略,v3 会使用 Accept-Language 标头或默认使用 en,而 v4 会默认使用该地点的本地语言和文字。
region regionCode 已重命名。如果省略,v3 默认为 us,而 v4 没有默认值。
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_id 通过地理编码 v3 获取特定地点 ID 的地址,则必须迁移到 v4 地点地理编码方法,该方法接受 GET 请求。

v4 API 更改了多个参数的名称、结构和支持。我们强烈建议您使用字段掩码来指定要在响应中返回的字段。

请求参数更改

v3 参数 v4 参数 备注
place_id 请求 proto 中的 place 字段 地点 ID 现在作为路径参数 places/{place} 提供,例如:https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw。这会映射到基础请求中的地点字段。
language languageCode 已重命名。如果省略此参数,v3 会使用 Accept-Language 标头或默认为 en,而 v4 会默认为相应位置的本地语言和文字。
region regionCode 已重命名。如果省略,v3 默认为 us,而 v4 没有默认值。

响应字段更改

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 Hyperlocal Data 迁移到 Destinations

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 - 这是一个新的可选字段,其中包含导航点的人类可读名称,例如“5th Ave”。
  • location - 这是 LatLng 类型的地点,与 Geocoding API v3 中使用的格式不同。
  • travelModes - 这与 Geocoding API v3 中导航点的 restrictedTravelModes 字段类似。枚举值相同,唯一的区别是此字段现在表示导航点的可接受出行模式,而不是受限出行模式。
  • usage - 这是一个新字段,其中包含导航点支持的使用情形。

建筑轮廓

如需获取与 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.primary
  • destination.containingPlaces
  • destination.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。如果使用 API 密钥直接从客户端 JavaScript(例如在浏览器中)调用 v4 方法,您的 API 密钥会面临被盗用和滥用的高风险。

HTTP 引荐来源网址限制虽然有用,但不足以保护 Web 服务端点,因为攻击者可以通过在请求中伪造 Referer 标头来轻松绕过这些限制。

建议通过您自己的后端服务器使用 Geocoding API v4。 您的客户端应用应向此中间服务器发出请求,然后该服务器使用受保护的 API 密钥(例如,存储在环境变量或 Secret Manager 中的密钥)安全地调用 Google API。这样可确保您的 API 密钥永远不会在前端代码中公开。

满足客户端需求的替代方案

如果您有需要进行地理编码的客户端需求,请考虑使用以下现有客户端解决方案之一: