你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

JavaScript/TypeScript REST SDK 开发人员指南(预览版)

Azure Maps JavaScript/TypeScript REST SDK (JavaScript SDK) 支持使用 Azure Maps 搜索服务进行搜索,例如搜索地址、搜索城市或国家/地区的边界以及按坐标搜索。 本文可以帮助你开始构建包含 Azure Maps 功能的位置感知应用程序。

注意

Azure Maps JavaScript SDK 支持 LTS 版本的 Node.js。 有关详细信息,请参阅 Node.js 发布工作组

先决条件

提示

可以通过编程方式创建 Azure Maps 帐户。下面是使用 Azure CLI 的示例:

az maps account create --kind "Gen2" --account-name "myMapAccountName" --resource-group "<resource group>" --sku "G2"

创建 Node.js 项目

以下示例使用 npm 创建了一个新目录,然后创建了一个名为 mapsDemo 的 Node.js 程序:

mkdir mapsDemo
cd mapsDemo
npm init

安装搜索包

若要使用 Azure Maps JavaScript SDK,需要安装搜索包。 每个 Azure Maps 服务(包括搜索、路线规划、呈现和地理位置)都包含在其自身的包中。

npm install @azure-rest/maps-search

安装包后,在 mapsDemo 目录中创建一个 search.js 文件:

mapsDemo
+-- package.json
+-- package-lock.json
+-- node_modules/
+-- search.js

Azure Maps 服务

Service name npm 包 示例
搜索 @azure-rest/maps-search 搜索示例
Route @azure-rest/maps-route 路由示例
呈现 @azure-rest/maps-render 呈现示例
地理位置 @azure-rest/maps-geolocation 地理位置示例

创建 MapsSearchClient 并对其进行身份验证

创建用于访问 Azure Maps 搜索 API 的 credential 对象时,需要 MapsSearchClient 对象进行身份验证。 可以使用 Microsoft Entra 凭据或 Azure 订阅密钥进行身份验证。 有关身份验证的详细信息,请参阅向 Azure Maps 进行身份验证

提示

MapsSearchClient 是开发人员使用 Azure Maps 搜索库的主要接口。 请参阅 Azure Maps 搜索客户端库,详细了解可用的搜索方法。

使用 Microsoft Entra 凭据

可以使用 Azure 标识库对 Microsoft Entra ID 进行身份验证。 若要使用 DefaultAzureCredential 提供程序,需要安装 @azure/identity 包:

npm install @azure/identity

需要注册新的 Microsoft Entra 应用程序,并通过向服务主体分配所需角色来授予对 Azure Maps 的访问权限。 有关详细信息,请参阅在非 Azure 资源上托管守护程序。 此时将返回应用程序(客户端)ID、目录(租户)ID 和 和客户端密码。 复制这些值并将其存储在安全位置。 在后续步骤中需要用到这些值。

将 Microsoft Entra 应用程序的应用程序(客户端)ID、目录(租户)ID 和客户端机密的值以及映射资源的客户端 ID 设置为环境变量:

环境变量 描述
AZURE_CLIENT_ID 已注册的应用程序中的应用程序(客户端)ID
AZURE_CLIENT_SECRET 已注册的应用程序中客户端密码的值
AZURE_TENANT_ID 已注册的应用程序中的目录(租户)ID
MAPS_CLIENT_ID Azure Maps 帐户中的客户端 ID

可以将 .env 文件用于这些变量。 需要安装 dotenv 包:

npm install dotenv

接下来,在 mapsDemo 目录中添加 .env 文件并指定以下属性:

AZURE_CLIENT_ID="<client-id>"
AZURE_CLIENT_SECRET="<client-secret>"
AZURE_TENANT_ID="<tenant-id>"
MAPS_CLIENT_ID="<maps-client-id>"

创建环境变量后,可以在 JavaScript 代码中访问它们:

const MapsSearch = require("@azure-rest/maps-search").default; 
const { DefaultAzureCredential } = require("@azure/identity"); 
require("dotenv").config(); 
 
const credential = new DefaultAzureCredential(); 
const client = MapsSearch(credential, process.env.MAPS_CLIENT_ID); 

使用订阅密钥凭据

可以使用 Azure Maps 订阅密钥进行身份验证。 可以在 Azure Maps 帐户的“身份验证”部分找到订阅密钥,如以下屏幕截图所示:

Screenshot showing your Azure Maps subscription key in the Azure portal.

需要将订阅密钥传递到 Azure 核心身份验证包 提供的 AzureKeyCredential 类。 出于安全考虑,最好将密钥指定为环境变量,而不是将其包含在源代码中。

为此,请使用 .env 文件来存储订阅密钥变量。 需要安装 dotenv 包才能检索值:

npm install dotenv

接下来,在 mapsDemo 目录中添加 .env 文件并指定属性:

MAPS_SUBSCRIPTION_KEY="<subscription-key>"

创建环境变量后,可以在 JavaScript 代码中进行访问:

const MapsSearch = require("@azure-rest/maps-search").default;
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();

const credential = new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY);
const client = MapsSearch(credential);

使用共享访问签名 (SAS) 令牌凭据

共享访问签名 (SAS) 令牌是使用 JSON Web 令牌 (JWT) 格式创建的身份验证令牌,通过加密签名来证明应用程序对 Azure Maps REST API 的身份验证。

可以使用 AzureMapsManagementClient.accounts.listSas 包获取 SAS 令牌。 首先按照创建 AzureMapsManagementClient 并对其进行身份验证部分进行设置。

然后,按照 Azure Maps 的托管标识为 Azure Maps 帐户创建托管标识。 复制托管标识的主体 ID(对象 ID)。

接着,安装 Azure Core 身份验证包使用 AzureSASCredential

npm install @azure/core-auth

最后,可以使用 SAS 令牌对客户端进行身份验证:

  const MapsSearch = require("@azure-rest/maps-search").default;
  const { AzureSASCredential } = require("@azure/core-auth");
  const { DefaultAzureCredential } = require("@azure/identity");
  const { AzureMapsManagementClient } = require("@azure/arm-maps");

  const subscriptionId = "<subscription ID of the map account>"
  const resourceGroupName = "<resource group name of the map account>";
  const accountName = "<name of the map account>";
  const mapsAccountSasParameters = {
    start: "<start time in ISO format>", // e.g. "2023-11-24T03:51:53.161Z"
    expiry: "<expiry time in ISO format>", // maximum value to start + 1 day
    maxRatePerSecond: 500,
    principalId: "<principle ID (object ID) of the managed identity>",
    signingKey: "primaryKey",
  };
  const credential = new DefaultAzureCredential();
  const managementClient = new AzureMapsManagementClient(credential, subscriptionId);
  const {accountSasToken} = await managementClient.accounts.listSas(
    resourceGroupName,
    accountName,
    mapsAccountSasParameters
  );
  if (accountSasToken === undefined) {
    throw new Error("No accountSasToken was found for the Maps Account.");
  }
  const sasCredential = new AzureSASCredential(accountSasToken);
  const client = MapsSearch(sasCredential);

地理编码

以下代码片段演示如何在简单的控制台应用程序中导入 @azure-rest/maps-search 包并使用 GetGeocoding 查询获取地址的坐标:

const MapsSearch = require("@azure-rest/maps-search").default;
const { isUnexpected } = require("@azure-rest/maps-search");
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();

async function main() {
  const credential = new AzureKeyCredential(
    process.env. MAPS_SUBSCRIPTION_KEY
  );
  const client = MapsSearch(credential);

  const response = await client.path("/geocode", "json").get({
    queryParameters: {
      query: "1301 Alaskan Way, Seattle, WA 98101, US",
    },
  });
  if (isUnexpected(response)) {
    throw response.body.error;
  }
  const [ lon, lat ] = response.body.features[0].geometry.coordinates;
  console.log(`The coordinate is: (${lat}, ${lon})`);
}

main().catch((err) => {
  console.error(err);
});

此代码片段演示了如何使用 Azure Maps 搜索客户端库中的 MapsSearch 方法借助 Azure 凭据创建 client 对象。 可以使用 Azure Maps 订阅密钥或 Microsoft Entra 凭据。 参数 path 可指定 API 终结点,在本例中为“/geocode”。 方法 get 使用查询参数发送 HTTP GET 请求。 该查询搜索“1301 Alaskan Way, Seattle, WA 98101, US”的坐标。 SDK 将结果作为 GeocodingResponseOutput 对象返回,并将其写入控制台。 结果按置信度分数排序,在本例中,屏幕上仅显示了返回的第一个结果。 有关详细信息,请参阅 GetGeocoding

使用 Node.js 运行 search.js

node search.js 

批量反向地理编码

Azure Maps 搜索还提供了一些批量查询方法。 以下示例演示如何调用批量反向搜索方法:

  const batchItems = [
    // This is an invalid query
    { coordinates: [2.294911, 148.858561] },
    {
      coordinates: [-122.34255, 47.6101],
    },
    { coordinates: [-122.33817, 47.6155] },
  ];
  const response = await client.path("/reverseGeocode:batch").post({
    body: { batchItems },
  });

在本例中,请求正文的 batchItems 中包括三个坐标。 第一项无效;如需显示如何处理无效项的示例,请参阅处理失败的请求

收到响应后,可对其进行记录:

 
function logResponseBody(resBody) {
  const { summary, batchItems } = resBody;

  const { totalRequests, successfulRequests } = summary;
  console.log(`${successfulRequests} out of ${totalRequests} requests are successful.`);

  batchItems.forEach(({ response }, idx) => {
    if (response.error) {
      console.log(`Error in ${idx + 1} request: ${response.error.message}`);
    } else {
      console.log(`Results in ${idx + 1} request:`);
      response.features.forEach((feature) => {
        console.log(`  ${feature.properties.address.freeformAddress}`);
      });
    }
  });
} 

处理失败的请求

通过检查响应批处理项中的 error 属性来处理失败的请求。 请参阅下面已完成的批量反向搜索示例中的 logResponseBody 函数。

已完成的批量反向搜索示例

进行反向地址批量搜索示例的完整代码:

const MapsSearch = require("@azure-rest/maps-search").default,
  { isUnexpected } = require("@azure-rest/maps-search");
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();

async function main() {
  const credential = new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY);
  const client = MapsSearch(credential);

  const batchItems = [
    // This is an invalid query
    { coordinates: [2.294911, 148.858561] },
    {
      coordinates: [-122.34255, 47.6101],
    },
    { coordinates: [-122.33817, 47.6155] },
  ];

  const response = await client.path("/reverseGeocode:batch").post({
    body: { batchItems },
  });

  if (isUnexpected(response)) {
    throw response.body.error;
  }

  logResponseBody(resumeResponse.body);
}

function logResponseBody(resBody) {
  const { summary, batchItems } = resBody;

  const { totalRequests, successfulRequests } = summary;
  console.log(`${successfulRequests} out of ${totalRequests} requests are successful.`);

  batchItems.forEach(({ response }, idx) => {
    if (response.error) {
      console.log(`Error in ${idx + 1} request: ${response.error.message}`);
    } else {
      console.log(`Results in ${idx + 1} request:`);
      response.features.forEach((feature) => {
        console.log(`  ${feature.properties.address.freeformAddress}`);
      });
    }
  });
} 

main().catch(console.error);

使用 V1 SDK

我们正在努力使 V1 的所有功能在 V2 中可用,在此之前,请根据需要安装以下 V1 SDK 包:

npm install @azure-rest/map-search-v1@npm:@azure-rest/map-search@^1.0.0
npm install @azure-rest/map-search-v2@npm:@azure-rest/map-search@^2.0.0

然后,可以导入以下两个包:

const MapsSearchV1 = require("@azure-rest/map-search-v1").default;
const MapsSearchV2 = require("@azure-rest/map-search-v2").default;

以下示例演示如何创建一个可接受地址和搜索其周围 POI 的函数。 使用 V2 SDK 获取地址的坐标 (/geocode),使用 V1 SDK 搜索其周围的 POI (/search/nearby)。

const MapsSearchV1 = require("@azure-rest/map-search-v1").default;
const MapsSearchV2 = require("@azure-rest/map-search-v2").default;
const { AzureKeyCredential } = require("@azure/core-auth");
const { isUnexpected: isUnexpectedV1 } = require("@azure-rest/maps-search-v1");
const { isUnexpected: isUnexpectedV2 } = require("@azure-rest/maps-search-v2");
require("dotenv").config();

/** Initialize the MapsSearchClient */
const clientV1 = MapsSearchV1(new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY));
const clientV2 = MapsSearchV2(new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY));

async function searchNearby(address) {
  /** Make a request to the geocoding API */
  const geocodeResponse = await clientV2
    .path("/geocode")
    .get({ queryParameters: { query: address } });
  /** Handle error response */
  if (isUnexpectedV2(geocodeResponse)) {
    throw geocodeResponse.body.error;
  }

  const [lon, lat] = geocodeResponse.body.features[0].geometry.coordinates;
  
  /** Make a request to the search nearby API */
  const nearByResponse = await clientV1.path("/search/nearby/{format}", "json").get({
    queryParameters: { lat, lon },
  });
  /** Handle error response */
  if (isUnexpectedV1(nearByResponse)) {
    throw nearByResponse.body.error;
  }
  /** Log response body */
  for(const results of nearByResponse.body.results) {
    console.log(
      `${result.poi ? result.poi.name + ":" : ""} ${result.address.freeformAddress}. (${
        result.position.lat
      }, ${result.position.lon})\n`
    );
  }
}

async function main(){
  searchNearBy("15127 NE 24th Street, Redmond, WA 98052");
}

main().catch((err) => {
    console.log(err);
})

其他信息