使用无服务器 API 创建静态 Web 应用

了解如何在本地运行,然后使用无服务器 API 将静态 Web 应用部署到 Azure。 本教程使用 最新 Azure Functions Node.js 编程模型的预览版。 由于本文使用 Azure Functions 的预览版,因此它部署为与静态 Web 应用不同的应用。

了解如何:

  • 使用 Azure 函数应用本地运行静态 Web 应用 (SWA)
  • 使用 SWA CLI 向本地后端 API 发出本地代理前端请求。
  • 远程部署并运行同一代码。

静态 Web 应用 CLI 提供的前端和后端端之间的代理提供:

  • React /api/todo中的 URL 未指定 API 的服务器或端口号。 使用此 URL 的请求在本地可成功执行,因为 SWA CLI 会为你管理代理。
  • 访问 /.auth/login/<provider> 时使用的本地身份验证仿真器
  • 路由管理和授权

此示例中的身份验证

此示例中的身份验证为 Azure Static Web 应用 服务中的前端用户提供:

  • 登录/注销
  • 公共和专用内容

此示例中的源代码

此示例中的源代码旨在了解如何使用无服务器 API 生成和部署静态 Web 应用。 代码不适用于生产。

可以在代码中找到不遵循最佳安全做法的多个位置。 例如,代码用于 console.log 写入浏览器控制台。

迁移到生产环境时,应查看并删除任何违反组织安全最佳做法的代码。

1. 准备开发环境

创建以下帐户:

在本地开发计算机上安装以下内容:

2.在 GitHub 上创建示例存储库分支

需要拥有示例存储库的分支才能从 GitHub 完成部署。 在分叉过程中,只需复制 main 分支。

分支 示例存储库https://github.com/Azure-Samples/azure-typescript-e2e-apps.

3.克隆分叉示例存储库

  1. 在 bash 终端中,将分支存储库克隆到本地计算机。 请勿克隆原始示例存储库。 示例 URL 为 https://github.com/YOUR-ACCOUNT-NAME/azure-typescript-e2e-apps

    git clone YOUR-FORKED-REPO-URL
    
  2. 安装本地前端应用的依赖项:

    cd app-react-vite && npm install 
    
  3. 安装本地后端应用的依赖项:

    cd ../apiV4-inmemory && npm install && cd ..
    

4.可选,生成并运行本地应用

示例存储库包含多个版本的前端和后端应用。 以下步骤使用前端的 React 18 (Vite) 版本,使用带有 Node.js 版本的后端/status/todo和 API 路由的 Azure Function v4。

  1. 在示例应用的根目录中,将 SWA CLI 与文件配合使用 ./swa-cli.config.json 以生成前端和后端应用:

    swa build
    

    如果遇到错误(具体可能取决于各种包和环境的版本),请先消除错误再继续操作。 请务必知道,在迁移到 Azure 静态Web 应用之前,项目在本地成功生成。

  2. 在示例应用的根目录中,使用 SWA CLI 通过代理启动应用。

    swa start
    
  3. 在 bash 终端中看到以下行时,该项目已成功启动。

    [swa] Serving static content:
    [swa]   /workspaces/azure-typescript-e2e-apps/app-react-vite/dist
    [swa] 
    [swa] Serving API:
    [swa]   /workspaces/azure-typescript-e2e-apps/api-inmemory
    [swa] 
    [swa] Azure Static Web Apps emulator started at http://0.0.0.0:4280. Press CTRL+C to exit.
    
  4. 打开代理 URL 的 Web 浏览器。 http://localhost:4280 应看到以下页面:

    Screenshot of local React app prior to authentication.

  5. 可以使用 SWA CLI 提供的身份验证登录。 该过程模拟基于云的 Azure 静态 Web 应用中的身份验证。 前端代码使用 /.auth/me 终结点获取用户的标识。 输入任何假用户名,不更改其余字段。

    Screenshot of local React app's mock authentication form.

  6. 用户进行身份验证后,前端会显示 专用 信息,例如 API 的环境变量。

    Screenshot of local React app with authentication complete.

    此 API 的 Azure Function v4 应用源代码为:

    import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
    
    import { name, version } from '../../package.json';
    function isObject(v) {
        return '[object Object]' === Object.prototype.toString.call(v);
    };
    function sortJson(o){
        if (Array.isArray(o)) {
            return o.sort().map(sortJson);
        } else if (isObject(o)) {
            return Object
                .keys(o)
            .sort()
                .reduce(function(a, k) {
                    a[k] = sortJson(o[k]);
    
                    return a;
                }, {});
        }
        return o;
    }
    
    export async function status(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
        context.log(`Http function processed request for url "${request.url}"`);
    
        const sortedEnv = sortJson(process.env);
    
        return { jsonBody: {
            name,
            version,
            env: sortedEnv,
            requestHeaders: request.headers 
        }};
    };
    
    app.http('status', {
        route: "status",
        methods: ['GET'],
        authLevel: 'anonymous',
        handler: status
    });
    
  7. 展开公共和专用部分以查看显示 API 中的内容。

5.创建新的 Azure Functions 应用

使用 API 运行静态 Web 应用的上一部分是可选的。 本文的其余部分是将应用和 API 部署到 Azure 云所必需的。

若要使用 Azure Functions v4 运行时的预览版本,需要创建新的 Azure Functions 应用。 还需要重新生成和重新部署静态 Web 应用,以在提取请求中使用 API 中的 Azure Functions 应用 URI,而不是使用代理和托管 API。

  1. 在 Web 浏览器中,打开Azure 门户以创建新的 Azure Functions 应用:创建新应用

  2. 使用以下信息创建 Function App:

    Tab:Setting
    基础知识:订阅 选择要使用的订阅。
    基础知识:资源组 创建新的资源组,例如 first-static-web-app-with-api。 该名称不会在应用的公共 URL 中使用。 资源组可帮助你对相关的 Azure 资源进行分组和管理。
    基础知识:实例详细信息:函数应用名称 输入全局唯一名称,例如 swa-api 在末尾添加 3 个随机字符,例如 swa-api-123
    基础知识:实例详细信息:代码或容器 选择Code
    基础知识:实例详细信息:运行时堆栈 选择 Node.js
    基础知识:实例详细信息:运行时堆栈 选择18LTS
    基础知识:操作系统 选择 Linux
    基础知识:托管 选择Consumption
    存储:存储帐户 请勿更改此项。 将创建一个新的Azure 存储帐户,以帮助处理函数事件。
    网络 不要更改任何内容。
    监视:Application Insights:启用 Application Insights 选择Yes。 不要更改提供的默认名称。
    部署:GitHub Actions 设置:持续部署 选择 Enable
    部署:GitHub 帐户 选择 GitHub 帐户。
    部署:组织 选择在创建示例存储库分支时使用的 GitHub 帐户。
    部署:存储库 选择分叉存储库名称 azure-typescript-e2e-apps
    部署:分支 选择main
    标记 不要更改任何内容。
    查看 + 创建 选择Create

    此步骤将 GitHub yaml 工作流文件添加到分支存储库。

  3. 创建资源后,选择 Go to resource 该按钮。

  4. 选择设置 -> 配置,然后为具有名称和AzureWebJobsFeatureFlags值的 EnableWorkerIndexingAzure Function Node.js v4 运行时添加配置设置。

  5. 选择“保存”,保存设置。

  6. 在 bash 终端中,使用 git 将新的 yaml 工作流文件从 GitHub 分支存储库拉取到本地计算机。

    git pull origin main
    
  7. 在 Visual Studio Code 中,打开位于 ./.github/workflows/ 的新 yaml 工作流文件。

  8. 提供的默认工作流文件假定函数源代码位于存储库的根目录中,并且是存储库中唯一的应用,但此示例并非如此。 若要解决此问题,请编辑该文件。 要编辑的行突出显示在以下 yaml 块中,并在下面进行了说明:

    # Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
    # More GitHub Actions for Azure: https://github.com/Azure/actions
    
    # Deploy Azure Functions Node.js v4 runtime
    # with api-inmemory subdir
    
    name: Azure Function App - api-inmemory
    
    on:
      push:
        branches:
          - main
        paths:
          - 'api-inmemory/**'
      workflow_dispatch:
    
    env:
      AZURE_FUNCTIONAPP_PACKAGE_PATH: 'api-inmemory' # set this to the path to your web app project, defaults to the repository root
      NODE_VERSION: '18.x' # Azure Functions v4 runtime requires 18
      VERBOSE: true # For debugging
    
    jobs:
      build-and-deploy:
        runs-on: ubuntu-latest
        steps:
          - name: 'Checkout GitHub Action'
            uses: actions/checkout@v2
    
          - name: Setup Node ${{ env.NODE_VERSION }} Environment
            uses: actions/setup-node@v1
            with:
              node-version: ${{ env.NODE_VERSION }}
    
          - name: 'Resolve Project Dependencies Using Npm'
            shell: bash
            run: |
              pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
              npm install
              npm run build --if-present
              npm run test --if-present
              popd
          - name: 'Upload artifact for deployment job' # For debugging
            uses: actions/upload-artifact@v3
            with:
              name: azure-function-v4-app
              path: |
                ${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}
                !${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}/node_modules
                !${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}/dist          
          - name: 'Run Azure Functions Action'
            uses: Azure/functions-action@v1
            id: fa
            with:
              app-name: 'swa-api' # change this to your Azure Function app name
              slot-name: 'Production'
              package: ${{env.AZURE_FUNCTIONAPP_PACKAGE_PATH}}
              publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_123 }}
              scm-do-build-during-deployment: false
              enable-oryx-build: false
    
    属性更改 目的
    name 缩短名称,以便你可以轻松地在分支的 GitHub 操作列表中找到它。
    paths 添加路径部分以限制部署仅在 Azure Functions API 代码更改时运行。 编辑工作流文件时,可以手动触发部署。
    AZURE_FUNCTIONAPP_PACKAGE_PATH 对源代码使用子目录时,这需要是该子目录路径和名称。
    VERBOSE 此设置有助于调试生成和部署过程。
    命名步骤 Upload artifact for deployment job 此步骤创建可下载的项目。 调试哪些文件部署到 Azure 函数时非常有用。

    这是 Upload artifact for deployment job 可选的。 它用于了解和调试部署到 Azure Functions 的文件,或在单独的环境中使用这些文件。

  9. 保存该文件,然后使用 git 添加、提交并将其推送回 GitHub:

    git add .
    git commit -m "fix the workflow for a subdir"
    git push origin main
    
  10. 在浏览器中,在分支的操作区域中重新运行 GitHub 上的工作流。

    Screenshot of GitHub forked repository, showing how to rerun a GitHub action.

  11. 等待操作成功完成,然后继续操作。

  12. 在 Web 浏览器中,使用函数应用的外部 API 终结点验证已成功部署的应用。

    https://YOUR-FUNCTION-APP-NAME.azurewebsites.net/api/todo
    

    为内存中数据返回的 JSON 结果为:

    {
        "1": "Say hello"
    }
    
  13. 记下函数的 URL。 在下一部分中需要用到该内容。

  14. 你知道 Azure 函数应用正在云中工作。 现在,需要在云中创建静态 Web 应用才能使用 API。

6.创建新的 Azure 静态 Web 应用

此创建过程将相同的分叉 GitHub 示例存储库部署到 Azure。 将部署配置为仅使用前端应用。

  1. 打开Azure 门户并使用 Azure 帐户登录:Azure 门户

  2. 使用以下信息完成创建步骤:

    提示 设置
    订阅 选择要使用的订阅。
    资源组 选择 Create new 并输入资源组的新资源组,例如 first-static-web-app。 该名称不在应用的公共 URL 中使用。 资源组可帮助你对用于单个项目的资源进行分组。
    托管计划类型 选择 Free
    Azure Functions 和暂存详细信息 不要更改默认值。 未在静态 Web 应用中部署函数 API。
    部署详细信息 - 源 选择 GitHub
    部署详细信息 - GitHub 如有必要,请登录到 GitHub。
    部署详细信息 - 组织 选择 GitHub 帐户。
    部署详细信息 - 存储库 选择名为 azure-typescript-e2e-apps“的分叉存储库。
    部署详细信息 - 分支 main选择分支。
    生成详细信息 - 生成演示 选择 Custom
    生成详细信息 - 应用位置 输入 /app-react-vite
    生成详细信息 - Api 位置 留空
    生成详细信息 - 输出位置 输入前端输出目录的位置。 dist
  3. 依次选择“查看 + 创建”、“创建”。

  4. 创建资源后,选择 Go to resource 该按钮。

  5. 在“ 概述 ”页上,记下静态 Web 应用的 URL。 设置 Azure 函数的 CORS 设置时,在下一部分中需要用到该设置。

  6. 创建过程会在分叉的 GitHub 存储库中创建 GitHub yaml 工作流文件。 使用以下命令拉取该更改:

    git pull origin main
    
  7. 找到 ./.github/workflows/azure-static-web-apps-*.yml 的 GitHub 操作负责生成和部署前端应用。 编辑文件,为基于云的后端 API URL 添加环境变量。 要编辑的行在以下 yaml 块中突出显示,并在 yaml 块下方进行说明。

    name: Azure Static Web Apps CI/CD
    
    on:
      push:
        branches:
          - main
        paths:
          - 'app-react-vite/**'
      pull_request:
        types: [opened, synchronize, reopened, closed]
        branches:
          - main
        paths:
          - 'app-react-vite/**'      
      workflow_dispatch:
    
    jobs:
      build_and_deploy_job:
        if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.action != 'closed')
        runs-on: ubuntu-latest
        name: Build and Deploy Job
        steps:
          - uses: actions/checkout@v2
            with:
              submodules: true
          - name: Build And Deploy
            id: builddeploy
            uses: Azure/static-web-apps-deploy@v1
            with:
              azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_DUNE_123 }}
              repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
              action: "upload"
              ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
              # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
              app_location: "/app-react-vite" # App source code path
              api_location: "" # Api source code path - optional
              output_location: "dist" # Built app content directory - optional
              ###### End of Repository/Build Configurations ######
            env: 
              VITE_BACKEND_URI: https://swa-api-123.azurewebsites.net
              VITE_CLOUD_ENV: production
    
      close_pull_request_job:
        if: github.event_name == 'pull_request' && github.event.action == 'closed'
        runs-on: ubuntu-latest
        name: Close Pull Request Job
        steps:
          - name: Close Pull Request
            id: closepullrequest
            uses: Azure/static-web-apps-deploy@v1
            with:
              azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_DUNE_123 }}
              action: "close"
    
    属性更改 目的
    paths 添加路径部分以限制部署仅在 Azure Functions API 代码更改时运行。 编辑工作流文件时,可以手动触发部署。
    workflow_dispatch 仅在学习部署过程和调试 Vite 生成中的任何问题时添加。workflow_dispatch 删除此行,在继续本文以外的此源代码时。
    if ... || github.event_name == 'workflow_dispatch' workflow_dispatch仅当了解部署过程并调试 Vite 生成中的任何问题时,才允许生成生成事件。
    env 使用 Vite 在静态生成中添加 Azure 函数 API 的 URL 所需的环境变量。VITE_BACKEND_URL是 Azure 函数应用的 URL。 VITE_CLOUD_ENV 是一个参数,用于指示何时使用 VITE_BACKEND_URL URL。 不要对此示例使用 NODE_ENV ,因为它有意外的一面影响。
  8. 保存该文件,然后使用 git 添加、提交并将其推送回 GitHub:

    git add .
    git commit -m "fix the workflow for a subdir"
    git push origin main
    
  9. 在浏览器中,在分支的操作区域中为静态 Web 应用重新运行 GitHub 上的工作流。

  10. 前端应用部署到 Azure。 现在,需要配置 Azure 函数应用,以允许来自静态 Web 应用的 CORS 请求。

7. 为 Azure 函数应用配置 CORS

使用单独的 Azure Function 应用(而不是托管函数应用)时,需要配置 CORS 以允许来自静态 Web 应用的请求。

  1. 在Azure 门户中,打开 Azure 函数应用。
  2. API -> CORS 部分中,将静态 Web 应用的 URL 添加到允许的源列表。

8.测试静态 Web 应用

  1. 在浏览器中,打开静态 Web 应用。
  2. 与应用交互以登录、查看公共和专用信息,然后再次注销。

9. 清理本文系列中使用的所有资源

清理本文章系列中创建的所有资源。

  1. 在Azure 门户中删除资源组,这会删除静态 Web 应用和函数应用。
  2. 在 GitHub 门户中,删除分支存储库。

疑难解答

此示例保留 已知问题和解决方法的列表。 如果问题未列出,请 提出问题

静态 Web 应用和函数应用公共 URL

在每个资源的“概述”页上,始终可以在Azure 门户中找到静态 Web 应用的 URL 和函数应用的 URL。 默认情况下,这些 URL 是公共的。

后续步骤