教程:在 Azure 应用服务中托管启用了 CORS 的 RESTful API

Azure 应用服务提供高度可缩放、自修复的 Web 托管服务。 另外,应用服务还为 RESTful API 提供对跨域资源共享 (CORS) 的内置支持。 本教程介绍如何将 ASP.NET Core API 应用部署到提供 CORS 支持的应用服务。 请使用命令行工具来配置应用,使用 Git 来部署应用。

在本教程中,你将了解如何执行以下操作:

  • 使用 Azure CLI 创建应用服务资源
  • 使用 Git 将 RESTful API 部署到 Azure
  • 启用应用服务 CORS 支持

可以在 macOS、Linux、Windows 中执行本教程中的步骤。

如果没有 Azure 订阅,可在开始前创建一个试用帐户

先决条件

为完成此教程:

创建本地 ASP.NET Core 应用

在此步骤中,请设置本地 ASP.NET Core 项目。 应用服务支持以其他语言编写的适用于 API 的同一工作流。

克隆示例应用程序

  1. 在终端窗口中,通过 cd 转到工作目录。

  2. 克隆示例存储库并更改为存储库根目录。

    git clone https://github.com/Azure-Samples/dotnet-core-api
    cd dotnet-core-api
    

    此存储库包含基于以下教程创建的应用:使用 Swagger 的 ASP.NET Core Web API 帮助页。 它使用 Swagger 生成器来提供 Swagger UI 和 Swagger JSON 终结点。

  3. 确保默认分支为 main

    git branch -m main
    

    提示

    应用服务不需要更改分支名称。 但是,由于许多存储库将其默认分支更改为 main(请参阅更改部署分支),因此本教程还介绍如何从 main 部署存储库。

运行应用程序

  1. 运行以下命令,安装所需的包,运行数据库迁移并启动应用程序。

    dotnet restore
    dotnet run
    
  2. 在浏览器中导航到 http://localhost:5000/swagger,以便使用 Swagger UI。

    ASP.NET Core API running locally

  3. 导航到 http://localhost:5000/api/todo,此时会看到 ToDo JSON 项的列表。

  4. 导航到 http://localhost:5000 并使用浏览器应用。 稍后请将浏览器应用指向应用服务中的远程 API,以便测试 CORS 功能。 浏览器应用的代码位于存储库的 wwwroot 目录中。

  5. 在终端按 Ctrl+C 可随时停止 ASP.NET Core。

注意

在可以在由世纪互联运营的 Microsoft Azure 中使用 Azure CLI 之前,请先运行 az cloud set -n AzureChinaCloud 来更改云环境。 若要切换回 Azure 公有云,请再次运行 az cloud set -n AzureCloud

将应用部署到 Azure

在此步骤中,将 .NET Core 应用程序部署到应用服务。

配置本地 Git 部署

可以使用“deployment user”将 FTP 和本地 Git 部署到 Azure Web 应用。 配置部署用户之后,可对所有 Azure 部署使用此用户。 帐户级部署用户名和密码不同于 Azure 订阅凭据。

若要配置部署用户,请在 Azure CLI 中运行 az webapp deployment user set 命令。 将 <username> 和 <password> 替换为部署用户的用户名和密码。

  • 用户名在 Azure 中必须唯一,并且为了本地Git推送,不能包含“@”符号。
  • 密码必须至少为 8 个字符,且具有字母、数字和符号这三种元素中的两种。
az webapp deployment user set --user-name <username> --password <password>

JSON 输出会将该密码显示为 null。 如果收到 'Conflict'. Details: 409 错误,请更改用户名。 如果收到 'Bad Request'. Details: 400 错误,请使用更强的密码。

请记录你要用于部署 Web 应用的用户名和密码。

创建资源组

资源组是在其中部署和管理 Azure 资源(例如 Web 应用、数据库和存储帐户)的逻辑容器。 例如,可以选择在使用完之后通过一个简单的步骤删除整个资源组。

在 Azure CLI 中,使用 az group create 命令创建资源组。 以下示例在“中国北部”位置创建名为“myResourceGroup”的资源组。 若要查看“免费”层中应用服务支持的所有位置,请运行 az appservice list-locations --sku FREE 命令。

az group create --name myResourceGroup --location "China North"

通常在附近的区域中创建资源组和资源。

此命令完成后,JSON 输出会显示资源组属性。

创建应用服务计划

使用 az appservice plan create 命令创建应用服务计划。

以下示例在免费定价层中创建名为 myAppServicePlan 的应用服务计划:

az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku FREE

创建应用服务计划后,Azure CLI 会显示类似于以下示例的信息:

{ 
  "adminSiteName": null,
  "appServicePlanName": "myAppServicePlan",
  "geoRegion": "China North",
  "hostingEnvironmentProfile": null,
  "id": "/subscriptions/0000-0000/resourceGroups/myResourceGroup/providers/Microsoft.Web/serverfarms/myAppServicePlan",
  "kind": "app",
  "location": "China North",
  "maximumNumberOfWorkers": 1,
  "name": "myAppServicePlan",
  < JSON data removed for brevity. >
  "targetWorkerSizeId": 0,
  "type": "Microsoft.Web/serverfarms",
  "workerTierName": null
} 

创建 Web 应用

myAppServicePlan 应用服务计划中创建一个 Web 应用

在 Azure CLI 中,可以使用 az webapp create 命令。 在以下示例中,将 <app-name> 替换为全局唯一的应用名称(有效字符是 a-z0-9-)。

az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name <app-name> --deployment-local-git

创建 Web 应用后,Azure CLI 会显示类似于以下示例的输出:

Local git is configured with url of 'https://<username>@<app-name>.scm.chinacloudsites.cn/<app-name>.git'
{
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "clientCertExclusionPaths": null,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "<app-name>.chinacloudsites.cn",
  "deploymentLocalGitUrl": "https://<username>@<app-name>.scm.chinacloudsites.cn/<app-name>.git",
  "enabled": true,
  < JSON data removed for brevity. >
}

注意

Git 远程的 URL 将显示在 deploymentLocalGitUrl 属性中,其格式为 https://<username>@<app-name>.scm.chinacloudsites.cn/<app-name>.git。 保存此 URL,后续将会用到。

从 Git 推送到 Azure

  1. 由于要部署 main 分支,因此需要将应用服务应用的默认部署分支设置为 main(请参阅main)。 在 Cloud Shell 中,使用 az webapp config appsettings set 命令设置 DEPLOYMENT_BRANCH 应用设置。

    az webapp config appsettings set --name <app-name> --resource-group myResourceGroup --settings DEPLOYMENT_BRANCH='main'
    
  2. 回到本地终端窗口,将 Azure 远程功能添加到本地 Git 存储库。 将 deploymentLocalGitUrl-from-create-step> 替换为从>保存的 Git 远程 URL。

    git remote add azure <deploymentLocalGitUrl-from-create-step>
    
  3. 使用以下命令推送到 Azure 远程库以部署应用。 当 Git 凭据管理器提示输入凭据时,请确保输入在配置部署用户中创建的凭据,而不是用于登录到 Azure 门户的凭据。

    git push azure main
    

    此命令可能需要花费几分钟时间运行。 运行时,该命令会显示类似于以下示例的信息:

   Enumerating objects: 83, done.
   Counting objects: 100% (83/83), done.
   Delta compression using up to 8 threads
   Compressing objects: 100% (78/78), done.
   Writing objects: 100% (83/83), 22.15 KiB | 3.69 MiB/s, done.
   Total 83 (delta 26), reused 0 (delta 0)
   remote: Updating branch 'master'.
   remote: Updating submodules.
   remote: Preparing deployment for commit id '509236e13d'.
   remote: Generating deployment script.
   remote: Project file path: .\TodoApi.csproj
   remote: Generating deployment script for ASP.NET MSBuild16 App
   remote: Generated deployment script files
   remote: Running deployment command...
   remote: Handling ASP.NET Core Web Application deployment with MSBuild16.
   remote: .
   remote: .
   remote: .
   remote: Finished successfully.
   remote: Running post deployment command(s)...
   remote: Triggering recycle (preview mode disabled).
   remote: Deployment successful.
   To https://<app_name>.scm.chinacloudsites.cn/<app_name>.git
   * [new branch]      master -> master
   

转到 Azure 应用

  1. 在浏览器中导航到 http://<app_name>.chinacloudsites.cn/swagger,开始使用 Swagger UI。

    ASP.NET Core API running in Azure App Service

  2. 导航到 http://<app_name>.chinacloudsites.cn/swagger/v1/swagger.json 即可看到已部署 API 的 swagger.json

  3. 导航到 http://<app_name>.chinacloudsites.cn/api/todo 即可看到已部署 API 正在运行。

添加 CORS 功能

接下来,在适用于 API 的应用服务中启用内置的 CORS 支持。

在示例应用中测试 CORS

  1. 在本地存储库中,打开 wwwroot/index.html

  2. 在第 51 中,将 apiEndpoint 变量设置为已部署 API 的 URL (http://<app_name>.chinacloudsites.cn)。 在应用服务中将 <appname> 替换为你的应用名称。

  3. 在本地终端窗口中,再次运行示例应用。

    dotnet run
    
  4. 导航到浏览器应用 (http://localhost:5000)。 在浏览器中打开开发人员工具窗口(在用于 Windows 的 Chrome 中使用 Ctrl+Shift+i),检查“控制台”选项卡。 此时会看到错误消息:No 'Access-Control-Allow-Origin' header is present on the requested resource

    CORS error in browser client

    浏览器应用 (http://localhost:5000) 和远程资源 (http://<app_name>.chinacloudsites.cn) 之间的域不匹配被浏览器识别为跨域资源请求。 此外,由于 REST API(应用服务应用)未发送 Access-Control-Allow-Origin 标头,因此浏览器已阻止加载跨域内容。

    在生产中,浏览器应用会有一个公共 URL 而不是 localhost URL,但对 localhost URL 启用 CORS 的方式与对公共 URL 相同。

启用 CORS

在 Windows 终端中,使用 az webapp cors add 命令对客户端的 URL 启用 CORS。 替换 <appname> 占位符。

az webapp cors add --resource-group myResourceGroup --name <app-name> --allowed-origins 'http://localhost:5000'

可以通过多次运行该命令或在 --allowed-origins 中添加逗号分隔列表来添加多个允许的源。 若要允许所有源,请使用 --allowed-origins '*'

再次测试 CORS

刷新浏览器应用 (http://localhost:5000)。 “控制台”窗口中的错误消息现在已消失, 可以看到已部署 API 中的数据并与之交互。 远程 API 现在支持对本地运行的浏览器应用使用 CORS。

CORS success in browser client

恭喜!你在包含 CORS 支持的 Azure 应用服务中运行了 API。

常见问题

应用服务 CORS 与你的 CORS 的比较

为了提高灵活性,可以使用自己的 CORS 实用程序而不是应用服务 CORS。 例如,可能需要针对不同的路由或方法指定不同的允许的源。 由于应用服务 CORS 允许你为所有 API 路由和方法指定一组接受的源,因此你需要使用自己的 CORS 代码。 请参阅启用跨域请求 (CORS),了解 ASP.NET Core 如何这样做。

内置应用服务 CORS 没有只允许指定的每个源使用特定 HTTP 方法或谓词的选项。 它将自动允许每个定义的源使用所有方法和标头。 在代码中使用选项 .AllowAnyHeader().AllowAnyMethod() 时,此行为类似于 ASP.NET Core CORS 策略。

注意

请勿尝试将应用服务 CORS 与你自己的 CORS 代码一起使用。 一起使用时,应用服务 CORS 优先级高,你自己的 CORS 代码将无效。

如何将允许的源设置为通配符子域?

*.contoso.com 这样的通配符子域比通配符源 * 更具限制性。 但在 Azure 门户中,应用的 CORS 管理页面不允许将通配符子域设置为允许的源。 不过,你可以使用 Azure CLI 执行此操作,如下所示:

az webapp cors add --resource-group <group-name> --name <app-name> --allowed-origins 'https://*.contoso.com'

如何在响应中启用 ACCESS-CONTROL-ALLOW-CREDENTIALS 标头?

如果应用要求发送凭据(例如 Cookie 或身份验证令牌),则浏览器会要求在响应中包含 ACCESS-CONTROL-ALLOW-CREDENTIALS 标头。 若要在应用服务中启用此功能,请将 properties.cors.supportCredentials 设置为 true

az resource update --name web --resource-group <group-name> \
  --namespace Microsoft.Web --resource-type config \
  --parent sites/<app-name> --set properties.cors.supportCredentials=true

当允许的源包含通配符源 '*' 时,不允许此操作。 指定 AllowAnyOriginAllowCredentials 是不安全的配置,可能会导致跨网站请求伪造。 若要允许凭据,请尝试将通配符源替换为通配符子域

清理资源

在前面的步骤中,你在资源组中创建了 Azure 资源。 如果认为将来不需要这些资源,请在本地 Azure CLI 中运行以下命令删除资源组:

az group delete --name myResourceGroup

此命令可能需要花费一点时间运行。

后续步骤

你已了解:

  • 使用 Azure CLI 创建应用服务资源
  • 使用 Git 将 RESTful API 部署到 Azure
  • 启用应用服务 CORS 支持

转到下一教程,了解如何对用户进行身份验证和授权。