快速入门:使用 Azure Functions 生成可缩放的 Web API

在本快速入门中,你将使用 Azure 开发人员命令行工具生成一个可缩放的 Web API,其中包含响应 HTTP 请求的函数终结点。 在本地测试代码后,将其部署到你创建的在 Azure Functions 的 Flex 消耗计划中运行的新无服务器函数应用中。

项目源使用 Azure Developer CLI (azd) 来简化将代码部署到 Azure 的过程。 此部署遵循安全且可缩放的 Azure Functions 部署的当前最佳做法。

默认情况下,弹性使用计划遵循按使用量付费计费模型,这意味着完成本快速入门在您的 Azure 帐户上只产生几分钱人民币或更少的费用。

先决条件

初始化项目

azd init使用命令从模板创建本地 Azure Functions 代码项目。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-dotnet-azd -e httpendpoint-dotnet
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 它也在 Azure 中你创建的资源组名称中使用。

  2. 运行此命令以导航到 http 应用文件夹:

    cd http
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json http的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template azure-functions-java-flex-consumption-azd -e httpendpoint-java 
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 它也在 Azure 中你创建的资源组名称中使用。

  2. 运行此命令以导航到 http 应用文件夹:

    cd http
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json http的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "java"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-javascript-azd -e httpendpoint-js
    

    此命令从模板存储库中拉取项目文件,并在根文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 它也在 Azure 中你创建的资源组名称中使用。

  2. 在包含此 JSON 数据的根文件夹中创建名为 local.settings.json 的文件

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "node"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-powershell-azd -e httpendpoint-ps
    

    此命令从模板存储库中拉取项目文件,并在根文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 它也在 Azure 中你创建的资源组名称中使用。

  2. 运行此命令以导航到 src 应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "powershell",
            "FUNCTIONS_WORKER_RUNTIME_VERSION": "7.2"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-typescript-azd -e httpendpoint-ts
    

    此命令从模板存储库中拉取项目文件,并在根文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 在包含此 JSON 数据的根文件夹中创建名为 local.settings.json 的文件

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "node"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-python-http-azd -e httpendpoint-py
    

    此命令从模板存储库中拉取项目文件,并在根文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 在包含此 JSON 数据的根文件夹中创建名为 local.settings.json 的文件

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "python"
        }
    }
    

    在本地运行时,需要此文件。

创建并激活虚拟环境

在根文件夹中,运行以下命令以创建并激活一个名为 .venv 的虚拟环境:

python3 -m venv .venv
source .venv/bin/activate

如果 Python 未在 Linux 分发版上安装 venv 包,请运行以下命令:

sudo apt-get install python3-venv

在本地环境中运行

  1. 在终端或命令提示符下从应用文件夹运行以下命令:

    func start
    
    mvn clean package
    mvn azure-functions:run
    
    npm install
    func start  
    
    npm install
    npm start  
    

    当 Functions 主机在本地项目文件夹中启动时,它会将 HTTP 触发函数的 URL 终结点写入终端输出。

    注意

    由于在本地运行时不会强制实施访问密钥授权,因此返回的函数 URL 不包括访问密钥值,并且不需要它调用函数。

  2. 在浏览器中,转到 httpget 端点,该 URL 应如下所示:

    http://localhost:7071/api/httpget

  3. 在新终端或命令提示符窗口中运行此 curl 命令,向 httppost 终结点发送带有 JSON 有效负载的 POST 请求:

    curl -i http://localhost:7071/api/httppost -H "Content-Type: text/json" -d @testdata.json
    
    curl -i http://localhost:7071/api/httppost -H "Content-Type: text/json" -d "@src/functions/testdata.json"
    

    此命令从 testdata.json 项目文件读取 JSON 有效负载数据。 可以在 test.http 项目文件中找到这两个 HTTP 请求的示例。

  4. 完成后,在终端窗口中按 Ctrl+C 停止 func.exe 主机进程。

  1. 运行 deactivate 以关闭虚拟环境。

查看代码(可选)

可以查看定义两个 HTTP 触发器函数终结点的代码:

        [Function("httpget")]
        public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get")]
          HttpRequest req,
          string name)
        {
            var returnValue = string.IsNullOrEmpty(name)
                ? "Hello, World."
                : $"Hello, {name}.";

            _logger.LogInformation($"C# HTTP trigger function processed a request for {returnValue}.");

            return new OkObjectResult(returnValue);
        }
    @FunctionName("httpget")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET},
                authLevel = AuthorizationLevel.FUNCTION)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        String name = Optional.ofNullable(request.getQueryParameters().get("name")).orElse("World");

        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
    }
const { app } = require('@azure/functions');

app.http('httpget', {
    methods: ['GET'],
    authLevel: 'function',
    handler: async (request, context) => {
        context.log(`Http function processed request for url "${request.url}"`);

        const name = request.query.get('name') || await request.text() || 'world';

        return { body: `Hello, ${name}!` };
    }
});
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";

export async function httpGetFunction(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || await request.text() || 'world';

    return { body: `Hello, ${name}!` };
};

app.http('httpget', {
    methods: ['GET'],
    authLevel: 'function',
    handler: httpGetFunction
});

function.json 文件定义 httpget 函数:

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get"
      ],
      "route": "httpget"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    }
  ]
}

run.ps1 文件实现函数代码:

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters
$name = $Request.Query.name

$body = "This HTTP triggered function executed successfully. Pass a name in the query string for a personalized response."

if ($name) {
    $body = "Hello, $name. This HTTP triggered function executed successfully."
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = [HttpStatusCode]::OK
    Body = $body
})
@app.route(route="httpget", methods=["GET"])
def http_get(req: func.HttpRequest) -> func.HttpResponse:
    name = req.params.get("name", "World")

    logging.info(f"Processing GET request. Name: {name}")

    return func.HttpResponse(f"Hello, {name}!")

可在此处查看完整的模板项目。

可在此处查看完整的模板项目。

可在此处查看完整的模板项目。

可在此处查看完整的模板项目。

可在此处查看完整的模板项目。

可在此处查看完整的模板项目。

在本地验证函数后,可以将其发布到 Azure。

部署到 Azure

此项目配置为使用 azd up 命令将此项目部署到 Azure 中 Flex 消耗计划中的新函数应用。

提示

该项目包括一组 Bicep 文件(在 infra 文件夹中), azd 用于创建安全部署到遵循最佳做法的 Flex 消耗计划。

  1. 运行以下命令,让 azd 在 Azure 中创建所需的 Azure 资源,并将代码项目部署到新的函数应用:

    azd up
    

    根文件夹包含 azure.yaml 所需的 azd 定义文件。

    如果尚未登录,系统会要求使用 Azure 帐户进行身份验证。

  2. 出现提示时,请提供以下所需的部署参数:

    参数 描述
    Azure 订阅 要在其中创建资源的订阅。
    Azure 位置 要在其中创建包含新 Azure 资源的资源组的 Azure 区域。 仅显示当前支持 Flex 消耗计划的区域。
    vnetEnabled 选择 False。 如果设置为 True ,部署将在新的虚拟网络中创建函数应用。

    azd up 命令结合你对这些提示的回答和 Bicep 配置文件来完成这些部署任务:

    • 创建和配置这些所需的 Azure 资源(等效于 azd provision):

      • Flex 消耗计划和函数应用
      • Azure 存储(必需)和 Application Insights(推荐)
      • 帐户的访问策略和角色
      • 使用托管标识(而不是存储的连接字符串)的服务到服务连接
      • (选项)用于安全运行函数应用和其他 Azure 资源的虚拟网络
    • 打包代码并将其部署到部署容器(等效于 azd deploy)。 然后,应用将启动并在已部署的包中运行。

    命令成功完成后,你会看到指向所创建资源的链接。

在 Azure 上调用函数

现在,可以通过使用 HTTP 测试工具或浏览器(对于 GET 请求)向其 URL 发出 HTTP 请求来调用 Azure 中的函数终结点。 函数在 Azure 中运行时,系统将强制实施访问密钥授权,你必须向请求提供函数访问密钥。

可以使用 Core Tools 获取 Azure 中运行的函数的 URL 终结点。

  1. 在本地终端或命令提示符下,运行以下命令以获取 URL 终结点值:

    SET APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME)
    func azure functionapp list-functions $APP_NAME --show-keys
    
    $APP_NAME = azd env get-value AZURE_FUNCTION_NAME
    func azure functionapp list-functions $APP_NAME --show-keys
    

    azd env get-value 命令从本地环境中获取函数应用名称。 使用--show-keysfunc azure functionapp list-functions选项时,返回的每个终结点的调用 URL值包括一个函数级访问密钥。

  2. 与之前一样,使用 HTTP 测试工具在 Azure 中运行的函数应用中验证这些 URL。

重新部署代码

azd up根据需要多次运行命令,以便预配 Azure 资源并将代码更新部署到函数应用。

注意

已部署的代码文件始终被最新的部署包覆盖。

azd 提示的初始响应和 azd 生成的任何环境变量都本地存储在你的命名环境中。 azd env get-values使用命令查看创建 Azure 资源时使用的环境中的所有变量。

清理资源

使用完函数应用和相关资源后,请使用此命令从 Azure 中删除函数应用及其相关资源,并避免产生任何进一步的成本:

azd down --no-prompt

注意

--no-prompt 选项指示 azd 在未经你确认的情况下删除资源组。

此命令不会影响本地代码项目。