如何使用AWS Amplify、Lambda、API Gateway和DynamoDB部署静态Web应用

构建现代Web应用通常涉及复杂的设置和服务器管理,但其实不必如此。Amazon Web Services(AWS)提供了一套强大的"无服务器"服务,让您能够构建和部署应用而无需担心底层基础设施。这意味着AWS会为您处理所有繁重的服务器、扩展和维护工作。

在本教程中,我们将引导您使用几个关键的AWS无服务器服务构建一个简单但功能完整的Web应用。您将学习如何将前端(用户看到的界面)与强大的后端(处理数据的部分)连接起来,实现自动高效的扩展。

目录

  • 我们将构建什么:无服务器求和计算器
  • 核心AWS服务介绍
  • 先决条件:需要准备什么
  • 开始构建:如何构建我们的无服务器Web应用
  • 如何测试应用:是否正常工作?
  • 常见问题及解决方案
  • 下一步:增强您的应用
  • 结论

我们将构建什么:无服务器求和计算器

我们将创建一个简单的求和计算器Web应用。该应用将允许用户输入两个数字,将其发送到我们的AWS后端进行计算,存储结果,然后将求和结果返回给用户。

计算器的工作流程如下:

  1. 接收用户输入:在简单网页中输入两个数字
  2. 后端处理:这些数字将发送到运行在AWS Lambda上的代码,进行相加计算
  3. 数据存储:计算详情(两个数字、它们的和以及计算时间)将保存在名为DynamoDB的高速数据库中
  4. 显示结果:求和结果将返回到网页并显示给用户

这个项目是理解无服务器架构核心概念以及不同AWS服务如何协同工作创建动态Web应用的绝佳方式。

核心AWS服务介绍

在深入之前,让我们熟悉将要使用的主要AWS服务。将它们视为专业工具,每个都有特定职责,共同构建我们的应用。

AWS Lambda:想象一下有一个只在收到特定任务时才激活的小机器人。这就是Lambda!它是"无服务器计算"服务,意味着您不需要管理任何服务器。只需上传代码(本例中的计算器逻辑),Lambda只在需要时运行它。

为什么使用它:它处理我们的后端数学计算(数字相加)。当用户请求求和时,Lambda"唤醒",执行计算,然后返回休眠状态。这很高效且成本效益高,因为您只需为代码实际运行时间付费。

Amazon API Gateway:将其视为后端的门卫或接待员。当您的网页想要与Lambda函数通信时,它不会直接对话。而是将请求发送到API Gateway。

为什么使用它:API Gateway安全地接收来自网页的请求(如"请计算这两个数字的和"),然后告诉正确的Lambda函数唤醒并处理它。它充当后端的安全入口点,确保只有授权请求才能通过。

Amazon DynamoDB:这是我们高速、灵活的数据库。与传统数据库不同,DynamoDB是NoSQL数据库,非常适合快速高效处理大量数据而无需固定结构。

为什么使用它:我们将使用DynamoDB存储计算历史(输入的数字及其和)。它设计用于处理大量流量而不会减慢速度,非常适合需要快速存储和检索数据的Web应用。

AWS Amplify:Amplify就像您的Web和移动应用个人施工队。它简化了构建、部署和托管前端应用的过程,并与其他AWS服务无缝集成。

为什么使用它:我们将使用Amplify托管简单的HTML、CSS和JavaScript网页。它提供了将网站上线互联网的简单方法,为我们处理所有复杂的部署步骤。

先决条件:需要准备什么

要跟随本教程,您应该具备:

  • AWS账户:这是访问所有AWS服务所必需的
  • Python基础知识:我们的后端逻辑将使用Python编写
  • REST API理解:了解API是什么以及RESTful API的工作原理会有帮助
  • HTML/CSS/JavaScript熟悉度:我们的前端将使用这些标准Web技术构建
  • NoSQL基础知识:虽然不是严格要求,但理解数据库中的键值对概念会有益

开始构建:如何构建我们的无服务器Web应用

我们将逐步构建应用,从数据库开始,然后是后端代码,通过API连接它们,最后部署前端。

步骤1:使用Amazon DynamoDB设置数据库

我们的计算器需要存储计算结果的地方。为此,我们将使用Amazon DynamoDB。

  1. 导航到DynamoDB控制台
    首先登录AWS管理控制台。在顶部搜索栏中输入"DynamoDB"并从结果中选择"DynamoDB"。这将带您进入DynamoDB仪表板。

  2. 创建新表
    在DynamoDB仪表板上,找到并点击"Create table"按钮。

  3. 配置表
    需要为表添加以下信息:

    • 表名:输入myTable
    • 分区键:输入ID

    分区键是DynamoDB中每个唯一项的主要标识符。将其视为每个记录的唯一ID号。它帮助DynamoDB快速查找和分布数据。

    保留所有其他设置为默认值。

  4. 完成表创建
    点击页面底部的"Create table"按钮。DynamoDB现在将创建您的表,通常需要几秒钟。

  5. 重要:记下表ARN
    表创建后,点击列表中的名称(myTable)进入其详细信息页面。在"Summary"选项卡下,您将找到显示"ARN"的部分。这是在AWS中唯一标识DynamoDB表的标识符。
    复制整个ARN并安全保存(如记事本)。稍后设置Lambda函数权限时需要它。

步骤2:使用AWS Lambda创建后端逻辑

现在我们有了数据库,让我们创建操作的核心:执行加法并保存结果的Lambda函数。

  1. 导航到Lambda控制台
    在AWS管理控制台搜索栏中输入"Lambda"并从结果中选择"Lambda"。这将带您进入Lambda仪表板。
    然后点击仪表板上的"Create function"按钮创建新函数。

  2. 配置函数
    配置您的函数:

    • 选择"Author from scratch"
    • 函数名:给函数起有意义的名字,例如SumCalculatorFunction
    • 运行时:选择"Python 3.9"(或可用的最新Python 3.x运行时)
    • 架构:保留为x86_64(默认)
    • 权限:暂时保留默认执行角色
  3. 创建函数
    点击底部的"Create function"按钮创建函数。

  4. 编写Lambda函数代码
    函数创建后,您将进入其配置页面。向下滚动到"Code source"部分。这是编写或粘贴Python代码的地方。
    您将看到默认的lambda_function.py文件。将其内容替换为以下Python代码:

import json
import boto3
import time
from botocore.exceptions import ClientError

# 创建DynamoDB客户端
dynamodb = boto3.resource('dynamodb')
# 指定要交互的DynamoDB表
table = dynamodb.Table('myTable')

def lambda_handler(event, context):
    # 从event数据中提取数字
    num1 = event.get('num1')
    num2 = event.get('num2')

    # 基本验证:检查是否提供了两个数字
    if num1 is None or num2 is None:
        return {
            'statusCode': 400,
            'body': json.dumps({'message': 'Both num1 and num2 are required'})
        }

    # 计算两个数字的和
    sum_result = num1 + num2

    # 为DynamoDB项生成唯一ID
    partition_key = str(int(time.time() * 1000))
    sort_key = str(int(time.time()))

    # 准备要存储在DynamoDB表中的数据
    item = {
        'ID': partition_key,
        'Timestamp': sort_key,
        'num1': num1,
        'num2': num2,
        'sum': sum_result
    }

    # 尝试将项存储在DynamoDB表中
    try:
        table.put_item(Item=item)
    except ClientError as e:
        return {
            'statusCode': 500,
            'body': json.dumps({'message': f'Error storing data in DynamoDB: {e.response["Error"]["Message"]}'})
        }

    # 如果一切成功,返回成功消息和计算详情
    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'Sum calculated and stored successfully',
            'result': {
                'ID': partition_key,
                'Timestamp': sort_key,
                'num1': num1,
                'num2': num2,
                'sum': sum_result
            }
        })
    }
  1. 部署代码
    粘贴代码后,点击代码编辑器上方的"Deploy"按钮。这将保存更改并使其生效。

  2. 测试Lambda函数
    代码部署后,测试Lambda函数(可选但推荐)。点击"Deploy"按钮旁边的"Test"按钮。系统将提示配置测试事件。
    选择"New event",对于"Event template",选择"hello-world"。将"Event JSON"框中的示例JSON替换为以下测试数据:

    { "num1": 5, "num2": 10 }
    

    给测试事件命名(例如testSum)。然后点击"Save"和"Test"。您应该看到"Status: Succeeded"消息,在"Execution result"选项卡中,您将看到statusCode: 200和计算的和。这确认了Lambda函数正常工作!

更新Lambda函数权限(IAM角色策略)

我们的Lambda函数当前具有默认权限,通常不包括访问DynamoDB的权限。我们需要明确授予它写入myTable的权限。我们将通过IAM角色策略实现。

  1. 导航到权限
    在Lambda函数配置页面上,点击"Configuration"选项卡。然后选择"Permissions"子选项卡。
    您将看到带有"Role name"的"Execution role"部分。点击此"Role name"(它将是一个链接)。这将带您进入IAM控制台,特别是与Lambda函数关联的角色详细信息。

  2. 添加权限
    在IAM角色页面上,您将看到标题为"Permissions policies"的部分。点击"Add permissions"然后选择"Create inline policy"。

  3. 配置策略
    您将看到"Policy editor"。点击"Visual editor"选项卡(如果尚未选择)。

    • 服务:点击"Choose a service"并搜索选择"DynamoDB"
    • 操作:在"Actions"部分,展开"Write"。搜索PutItem并选择复选框
    • 资源:点击"Specific",点击"Add ARN",粘贴之前从步骤1复制的DynamoDB表ARN
  4. 审查并创建策略
    点击"Next: Review policy"。给策略起有意义的名字,例如DynamoDBPutItemPolicy。
    审查策略JSON确保它授予对特定myTable ARN的dynamodb:PutItem权限。然后点击"Create policy"。

现在您的Lambda函数具有写入DynamoDB表所需的权限!

步骤3:使用Amazon API Gateway连接前端和后端

现在我们有了Lambda函数,我们需要让网页能够与之通信。这就是API Gateway的作用。

在AWS管理控制台搜索栏中输入"API Gateway"并从结果中选择"API Gateway"。

  1. 创建新API
    在API Gateway仪表板上,在"REST API"下,点击"Build"按钮。

  2. 配置API设置

    • 选择协议:选择REST
    • 创建新API:选择New API
    • API名称:给API起清晰的名字,例如SumCalculatorAPI
    • 端点类型:选择Regional(默认)
      然后点击"Create API"。
  3. 创建资源
    创建API后,您将进入其仪表板。从"Actions"下拉菜单中,选择"Create Resource"。

    • 资源名称:可以保留为calculator或任何有意义的名称
    • 路径部分:保留为/(根路径)
      然后点击"Create Resource"。
  4. 创建方法(POST)
    在左导航面板中选择根资源(/),从"Actions"下拉菜单中,选择"Create Method"。
    从出现的下拉列表中选择"POST"并点击旁边的复选标记按钮。
    设置详情:

    • 集成类型:选择Lambda Function
    • 使用Lambda代理集成:勾选此框
    • Lambda区域:选择创建Lambda函数的AWS区域
    • Lambda函数:开始输入Lambda函数名称并从下拉列表中选择
      然后点击"Save"。可能会弹出确认添加Lambda权限的窗口。点击"OK"。
  5. 启用CORS
    这是关键步骤!我们的前端(将托管在AWS Amplify上,不同的域)需要权限与API Gateway端点通信。
    仍然选择根资源(/),从"Actions"下拉菜单中,选择"Enable CORS"。将出现对话框。可以接受此简单应用的默认设置。确保POST在"Methods"下被选中,并且"Access-Control-Allow-Origin"设置为’*'。
    然后点击"Enable CORS and replace existing CORS headers"。提示时点击"Yes, replace existing values"。

  6. 部署API
    对API Gateway方法的更改在API"部署"到"阶段"之前不会生效。从"Actions"下拉菜单中,选择"Deploy API"。

    • 部署阶段:选择"[New Stage]"
    • 阶段名称:给阶段起名字,例如dev
    • 阶段描述:(可选)添加描述
      然后点击"Deploy"。
  7. 记下调用URL
    部署后,您将进入"Stages"视图。在左导航面板中点击新创建的阶段(例如dev)。
    您将看到"Invoke URL"。这是API端点的公共URL。
    复制整个调用URL并安全保存。这是我们的前端将用于向Lambda函数发送数字的URL!

步骤4:创建前端Web应用

现在我们的后端已准备好接收请求和处理计算,让我们构建用户将交互的简单网页。我们将使用基本的HTML、CSS和JavaScript。

您需要在计算机上的新文件夹中创建三个文件:index.html、app.js和style.css。

index.html(网页结构)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Sum Calculator</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>SUM CALCULATOR</h1>

    <form id="calculatorForm">
        <label for="num1">Number 1:</label>
        <input type="number" id="num1" required>

        <label for="num2">Number 2:</label>
        <input type="number" id="num2" required>

        <button type="submit" id="calculateBtn">
            <span id="btnText">CALCULATE</span>
            <span id="loadingSpinner" class="spinner d-none"></span> 
        </button>
    </form>

    <div id="errorAlert" class="alert d-none">
        <strong style="color: red;">Error!</strong> <span id="errorMessage"></span>
    </div>

    <div id="resultSection" class="result-box d-none">
        <h2>Calculation Result:</h2>
        <p><strong>Transaction ID:</strong> <span id="resultId"></span></p>
        <p><strong>Timestamp:</strong> <span id="resultTimestamp"></span></p>
        <p><strong>Numbers:</strong> <span id="resultNum1"></span> + <span id="resultNum2"></span></p>
        <p><strong>Sum:</strong> <span id="resultSum"></span></p>
    </div>

    <script src="app.js"></script>
</body>
</html>

app.js(前端逻辑)
记住将替换为从步骤3复制的实际调用URL!

document.addEventListener('DOMContentLoaded', function() {
    const API_ENDPOINT = 'https://YOUR_API_GATEWAY_INVOKE_URL_HERE.execute-api.us-east-1.amazonaws.com/dev';

    const calculatorForm = document.getElementById('calculatorForm');
    const num1Input = document.getElementById('num1');
    const num2Input = document.getElementById('num2');
    const calculateBtn = document.getElementById('calculateBtn');
    const btnText = document.getElementById('btnText');
    const loadingSpinner = document.getElementById('loadingSpinner');
    const errorAlert = document.getElementById('errorAlert');
    const errorMessage = document.getElementById('errorMessage');
    const resultSection = document.getElementById('resultSection');

    const resultId = document.getElementById('resultId');
    const resultTimestamp = document.getElementById('resultTimestamp');
    const resultNum1 = document.getElementById('resultNum1');
    const resultNum2 = document.getElementById('resultNum2');
    const resultSum = document.getElementById('resultSum');

    calculatorForm.addEventListener('submit', function(event) {
        event.preventDefault();

        errorAlert.classList.add('d-none');
        resultSection.classList.add('d-none');

        const num1 = parseFloat(num1Input.value);
        const num2 = parseFloat(num2Input.value);

        if (isNaN(num1) || isNaN(num2)) {
            showError('Please enter valid numbers');
            return;
        }

        setLoadingState(true);

        const requestData = {
            num1: num1,
            num2: num2
        };

        fetch(API_ENDPOINT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(requestData)
        })
        .then(response => {
            if (!response.ok) {
                return response.json().then(errData => {
                    throw new Error(errData.message || 'Server error');
                });
            }
            return response.json();
        })
        .then(data => {
            setLoadingState(false);

            if (data.statusCode && data.statusCode === 200 && data.body) {
                try {
                    const resultData = typeof data.body === 'string' 
                        ? JSON.parse(data.body) 
                        : data.body;

                    displayResult(resultData);
                } catch (err) {
                    showError('Error parsing the result: ' + err.message);
                }
            } else {
                showError('Unexpected API response format');
            }
        })
        .catch(error => {
            setLoadingState(false);
            showError(error.message || 'An error occurred while communicating with the API');
        });
    });

    function showError(message) {
        errorMessage.textContent = message;
        errorAlert.classList.remove('d-none');
    }

    function setLoadingState(isLoading) {
        if (isLoading) {
            btnText.textContent = 'Calculating...';
            loadingSpinner.classList.remove('d-none');
            calculateBtn.disabled = true;
        } else {
            btnText.textContent = 'CALCULATE';
            loadingSpinner.classList.add('d-none');
            calculateBtn.disabled = false;
        }
    }

    function displayResult(data) {
        if (!data.result) {
            showError('No result data in the API response');
            return;
        }

        const result = data.result;

        let timestampDisplay = result.Timestamp;
        if (result.Timestamp && !isNaN(result.Timestamp)) {
            const date = new Date(parseInt(result.Timestamp) * 1000);
            timestampDisplay = date.toLocaleString();
        }

        resultId.textContent = result.ID || 'N/A';
        resultTimestamp.textContent = timestampDisplay || 'N/A';
        resultNum1.textContent = result.num1;
        resultNum2.textContent = result.num2;
        resultSum.textContent = result.sum;

        resultSection.classList.remove('d-none');
    }
});

style.css(页面样式)

body {
    background-color: #222629;
    color: #FFFFFF;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
    padding: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    min-height: 100vh;
    margin: 0;
}

h1 {
    color: #86C232;
    margin-bottom: 30px;
}

label {
    font-size: 18px;
    margin-right: 10px;
    display: inline-block;
    width: 80px;
    text-align: right;
}

input[type="number"] {
    background-color: #333;
    border: 1px solid #444;
    color: #FFFFFF;
    padding: 8px 12px;
    font-size: 16px;
    border-radius: 5px;
    margin-bottom: 15px;
    width: 150px;
    outline: none;
}

input[type="number"]:focus {
    border-color: #86C232;
    box-shadow: 0 0 0 3px rgba(134, 194, 50, 0.5);
}

button {
    background-color: #86C232;
    border: none;
    color: #FFFFFF;
    font-size: 18px;
    font-weight: bold;
    padding: 10px 20px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 20px;
    width: 180px;
}

button:hover:not(:disabled) {
    background-color: #6a9b2b;
}

button:disabled {
    background-color: #555;
    cursor: not-allowed;
}

#calculatorForm {
    background-color: #333;
    padding: 30px;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 30px;
}

.spinner {
    border: 3px solid rgba(255, 255, 255, 0.3);
    border-top: 3px solid #FFFFFF;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.alert {
    background-color: #330d0d;
    border: 1px solid #ff4d4d;
    color: #ff4d4d;
    padding: 10px 15px;
    border-radius: 5px;
    margin-top: 20px;
    width: 100%;
    max-width: 400px;
    text-align: center;
}

.result-box {
    background-color: #333;
    border: 1px solid #86C232;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    width: 100%;
    max-width: 400px;
    margin-top: 20px;
    animation: fadeIn 0.5s ease-in-out;
}

.result-box h2 {
    color: #86C232;
    margin-top: 0;
    border-bottom: 1px solid #444;
    padding-bottom: 10px;
    margin-bottom: 15px;
}

.result-box p {
    margin-bottom: 8px;
}

.result-box strong {
    color: #99EE33;
}

.d-none {
    display: none !important;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

步骤5:使用AWS Amplify部署前端

最后,让我们使用AWS Amplify将前端Web应用上线。Amplify使托管静态网站变得异常简单。

  1. 准备前端文件
    确保所有三个文件(index.html、app.js、style.css)在计算机上的单个文件夹中。
    将此文件夹压缩为ZIP文件。确保index.html文件位于ZIP文件的根目录(不在ZIP内的另一个子文件夹中)。

  2. 导航到AWS Amplify控制台
    在AWS管理控制台搜索栏中输入"Amplify"并从结果中选择"AWS Amplify"。

  3. 无Git提供商部署
    在Amplify控制台上,您将看到连接到Git提供商的选项。为简化本教程,我们选择手动部署。
    在"Deploy without Git provider"下,点击"Deploy"。

  4. 上传文件

    • 应用名称:给应用起名字,例如SumCalculatorWebApp
    • 环境名称:可以使用dev或main
    • 拖放或浏览文件:点击"drag and drop"区域或"Choose files"按钮
    • 选择在步骤5.1中创建的ZIP文件
  5. 审查并部署
    现在点击"Save and Deploy"。Amplify将获取ZIP文件,提取其内容,并将静态网站部署到由AWS CloudFront提供的全球内容分发网络。这使您的网站在世界任何地方都能快速加载。此过程可能需要几分钟。

  6. 访问实时应用
    部署完成后,Amplify将提供"Domain" URL。点击此URL。这是您的实时公共Web应用!

如何测试应用:是否正常工作?

现在是最激动人心的部分——通过以下步骤测试我们完全无服务器的Web应用:

  1. 打开Amplify应用URL:导航到AWS Amplify提供的"Domain" URL
  2. 输入数字:在"Number 1"和"Number 2"输入字段中,输入任意两个数字(例如5和10)
  3. 点击"CALCULATE":点击"CALCULATE"按钮。您应该短暂看到按钮上显示"Calculating…"
  4. 观察结果:如果一切设置正确,您应该看到"Calculation Result"框出现在表单下方,显示交易ID、时间戳、数字及其和!
  5. 在DynamoDB中验证(可选):
    • 返回DynamoDB控制台
    • 点击myTable
    • 点击"Explore table items"选项卡
    • 您现在应该看到新条目,对应于在Web应用上执行的每个计算,存储了ID、时间戳、num1、num2和sum!

常见问题及解决方案

有时事情不会第一次就完美工作。以下是一些常见问题及解决方法:

CORS错误

  • 症状:Web浏览器开发者控制台显示错误,如"Access to fetch at ‘…’ from origin ‘…’ has been blocked by CORS policy"
  • 解决方案:返回步骤3第5部分(启用CORS)并确保已为API启用CORS。确保POST被选中且Access-Control-Allow-Origin正确配置

Lambda超时

  • 症状:Web应用持续显示"Calculating…“或出现通用错误,在Lambda函数日志中看到"Task timed out”
  • 解决方案:增加Lambda函数的"Timeout"设置

DynamoDB权限错误

  • 症状:Lambda函数执行失败,日志中看到错误如"User: … is not authorized to perform: dynamodb:PutItem on resource: …"
  • 解决方案:确保正确添加了dynamodb:PutItem操作并指定了myTable的ARN作为资源

不正确的API Gateway调用URL

  • 症状:前端发出请求但立即失败或浏览器控制台中出现网络错误
  • 解决方案:仔细检查app.js文件中的API_ENDPOINT常量是否与从API Gateway复制的调用URL完全一致

下一步:增强您的应用

这个计算器是一个很好的起点,但您可以显著扩展它:

  • 添加身份验证:实现用户登录和注册,使只有授权用户才能使用计算器
  • 实现错误处理:根据后端发送的内容显示特定错误消息,使前端更健壮
  • 创建计算历史视图:扩展前端以获取和显示DynamoDB中存储的所有过去计算列表
  • 添加输入验证:在前端和后端实现更健壮的验证以处理非数字输入或其他边缘情况
  • 实现实时更新:使用AWS AppSync或带有API Gateway的WebSocket将新计算结果实时推送到前端,无需页面刷新

结论

恭喜!您已成功在AWS上构建并部署了功能完整的无服务器Web应用。您已经了解了如何利用强大的服务如AWS Lambda、Amazon API Gateway、Amazon DynamoDB和AWS Amplify来创建可扩展、成本效益高且维护量低的应用。

这种架构非常强大,因为它可以自动扩展以处理数千甚至数百万用户,而您无需管理单个服务器。请记住在完成实验后清理AWS资源以避免不必要的费用。

进一步学习资源

  • AWS Lambda文档:深入了解无服务器函数
  • Amazon DynamoDB开发指南:了解更多关于NoSQL数据库的知识
  • Amazon API Gateway教程:探索构建各种类型的API
  • AWS Amplify文档:发现构建和部署全栈应用的更多功能
    更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
    公众号二维码
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐