返回首頁AWS Lambda

AWS Lambda + API Gateway 整合教學:建立 REST API 完整指南

15 min 分鐘閱讀
#AWS Lambda#API Gateway#REST API#HTTP API#Lambda Authorizer#Lambda Function URL#Serverless#JWT 驗證#CORS#API 設計

AWS Lambda + API Gateway 整合教學:建立 REST API 完整指南

引言:為什麼這個組合這麼受歡迎

想在 10 分鐘內建立一個可擴展的 API?

Lambda + API Gateway 是最快的方法。

不需要設定伺服器、不需要擔心擴展、不需要處理負載平衡。

寫好程式碼,設定好路由,部署完成。API 就上線了。

這就是 Serverless API 的魅力。

如果你還不熟悉 Lambda 的基本概念,建議先閱讀 AWS Lambda 完整指南

插圖 1:Lambda + API Gateway 架構示意圖

概念介紹

在動手之前,先理解這兩個服務如何協作。

API Gateway 是什麼

API Gateway 是 AWS 的 API 管理服務。

它負責:

  • 接收請求:處理 HTTP/HTTPS 請求
  • 認證授權:驗證 API Key、JWT Token、IAM 權限
  • 流量控制:速率限制、節流保護
  • 請求轉換:修改請求/回應格式
  • 監控記錄:CloudWatch 整合、存取日誌

簡單說,API Gateway 是你的 API 的「門面」。

所有外部請求先經過它,再轉發到後端服務(Lambda、EC2、其他 HTTP 端點)。

REST API vs HTTP API 差異

API Gateway 有兩種類型:REST API 和 HTTP API。

特性REST APIHTTP API
價格每百萬次 $3.50每百萬次 $1.00
延遲較高較低(約快 60%)
功能完整基本
API Key 管理
使用計畫
請求驗證
WAF 整合
私有端點
Lambda Authorizer

選擇建議:

  • 需要進階功能(WAF、請求驗證、使用計畫):選 REST API
  • 追求低成本和低延遲:選 HTTP API
  • 不確定:先用 HTTP API,需要時再升級

想了解更詳細的費用比較,請參考 AWS Lambda 費用計算完整指南

Lambda Proxy Integration 原理

Lambda Proxy Integration 是最常用的整合方式。

運作原理很直接:

  1. API Gateway 收到 HTTP 請求
  2. 把完整請求(包含 headers、body、path、query)封裝成 event 物件
  3. 傳給 Lambda 函數
  4. Lambda 回傳指定格式的回應
  5. API Gateway 將回應傳給客戶端

event 物件範例:

{
  "httpMethod": "POST",
  "path": "/users",
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer xxx"
  },
  "queryStringParameters": {
    "page": "1"
  },
  "body": "{\"name\": \"John\"}"
}

Lambda 回應格式(必須遵守):

{
  "statusCode": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": "{\"message\": \"success\"}"
}

如果回應格式不對,會出現 502 Bad Gateway 錯誤。這是最常見的問題。


實作步驟

來建立一個簡單的 API:GET /hello 回傳問候訊息。

Step 1:建立 Lambda 函數

使用 AWS Console:

  1. 前往 Lambda 服務
  2. 點擊「建立函數」
  3. 選擇「從頭開始撰寫」
  4. 函數名稱:hello-api
  5. 執行時間:Python 3.12
  6. 點擊「建立函數」

貼上程式碼:

import json

def lambda_handler(event, context):
    # 取得查詢參數
    name = "World"
    if event.get("queryStringParameters"):
        name = event["queryStringParameters"].get("name", "World")

    # 建立回應
    response = {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": "*"  # CORS
        },
        "body": json.dumps({
            "message": f"Hello, {name}!",
            "path": event.get("path", ""),
            "method": event.get("httpMethod", "")
        })
    }

    return response

點擊「Deploy」儲存。

Step 2:建立 API Gateway

建立 HTTP API(推薦新手使用):

  1. 前往 API Gateway 服務
  2. 點擊「建立 API」
  3. 選擇「HTTP API」→「建置」
  4. 新增整合:選擇「Lambda」
  5. 選擇剛才建立的 hello-api 函數
  6. API 名稱:my-hello-api
  7. 點擊「下一步」

Step 3:設定路由

在路由設定頁面:

  1. 方法:GET
  2. 資源路徑:/hello
  3. 整合目標:hello-api(Lambda 函數)
  4. 點擊「下一步」

Step 4:部署與測試

  1. 階段名稱:$default(或自訂如 prod
  2. 點擊「下一步」→「建立」

完成後,你會看到一個 Invoke URL,類似:

https://abc123xyz.execute-api.ap-northeast-1.amazonaws.com

測試 API:

# 基本測試
curl https://abc123xyz.execute-api.ap-northeast-1.amazonaws.com/hello

# 帶參數測試
curl "https://abc123xyz.execute-api.ap-northeast-1.amazonaws.com/hello?name=Claude"

如果看到 JSON 回應,恭喜!你的 Serverless API 已經上線了。


想把 API 架構做得更完善?預約架構諮詢,讓專家幫你設計。


Lambda Authorizer 實戰

API 上線了,但任何人都能存取。

接下來加上身份驗證。

Token-based vs Request-based

Lambda Authorizer 有兩種類型:

Token-based Authorizer:

  • 從 Authorization header 取得 token
  • 驗證 JWT、OAuth token 等
  • 適合標準的 Bearer Token 驗證

Request-based Authorizer:

  • 可以存取完整請求(headers、query、path)
  • 適合複雜的驗證邏輯
  • 例如:根據 IP + API Key 組合驗證

JWT 驗證實作範例

以下是一個驗證 JWT Token 的 Authorizer:

import json
import jwt  # 需要在 Lambda Layer 中安裝 PyJWT

SECRET_KEY = "your-secret-key"  # 實際使用請存在 Secrets Manager

def lambda_handler(event, context):
    try:
        # 取得 token
        token = event.get("authorizationToken", "")
        if token.startswith("Bearer "):
            token = token[7:]

        # 驗證 JWT
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        user_id = payload.get("sub")

        # 驗證成功,回傳 Allow policy
        return generate_policy(user_id, "Allow", event["methodArn"])

    except jwt.ExpiredSignatureError:
        raise Exception("Unauthorized")  # Token 過期
    except jwt.InvalidTokenError:
        raise Exception("Unauthorized")  # Token 無效

def generate_policy(principal_id, effect, resource):
    return {
        "principalId": principal_id,
        "policyDocument": {
            "Version": "2012-10-17",
            "Statement": [{
                "Action": "execute-api:Invoke",
                "Effect": effect,
                "Resource": resource
            }]
        },
        "context": {
            "userId": principal_id  # 可以傳遞額外資訊給後端 Lambda
        }
    }

IAM Policy 回傳格式

Authorizer 必須回傳特定格式的 IAM Policy:

{
  "principalId": "user123",
  "policyDocument": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow",
        "Resource": "arn:aws:execute-api:region:account:api-id/stage/method/path"
      }
    ]
  },
  "context": {
    "userId": "user123",
    "role": "admin"
  }
}

重點:

  • Effect 只能是 AllowDeny
  • context 的值只能是字串、數字、布林
  • 驗證失敗時直接 raise Exception("Unauthorized")

插圖 2:Lambda Authorizer 驗證流程圖

Lambda Function URL vs API Gateway

2022 年,AWS 推出了 Lambda Function URL。

這讓 Lambda 可以直接處理 HTTP 請求,不需要 API Gateway。

功能比較表

特性Function URLAPI Gateway
費用免費$1-3.5/百萬次
設定複雜度簡單中等
自訂網域較麻煩內建支援
速率限制
API Key 管理
快取
請求驗證
WAF 整合需透過 CloudFront
Lambda Authorizer
IAM 驗證

何時用 Function URL

適合使用 Function URL 的場景:

  • 內部服務之間的呼叫
  • 簡單的 Webhook 接收器
  • 開發測試環境
  • 成本敏感的低流量服務

設定 Function URL:

  1. 前往 Lambda 函數設定
  2. 選擇「組態」→「函數 URL」
  3. 點擊「建立函數 URL」
  4. 驗證類型:選擇 NONE(公開)或 AWS_IAM
  5. 點擊「儲存」

你會得到一個 URL 如:https://xxx.lambda-url.ap-northeast-1.on.aws/

何時一定要用 API Gateway

必須使用 API Gateway 的場景:

  • 需要速率限制保護 API
  • 需要 API Key 或使用計畫
  • 需要 WAF 保護
  • 需要自訂網域(較簡單的設定)
  • 需要 Lambda Authorizer
  • 需要請求/回應轉換
  • 需要快取減少 Lambda 呼叫

經驗法則:

  • 對外公開的 API:用 API Gateway
  • 內部服務呼叫:可以考慮 Function URL

不確定該選哪個方案? API 架構選擇會影響成本和擴展性。

預約架構諮詢,讓我們幫你分析最適合的方案。


效能最佳化

API 上線後,接下來優化效能。

Keep-Alive 連線

Lambda 在呼叫外部服務時,應該重用 HTTP 連線。

Python 範例:

import urllib3

# 在 Handler 外建立連線池
http = urllib3.PoolManager()

def lambda_handler(event, context):
    # 重用連線
    response = http.request('GET', 'https://api.example.com/data')
    return {
        'statusCode': 200,
        'body': response.data.decode('utf-8')
    }

這可以減少每次請求的連線建立時間。

回應壓縮

對於較大的回應,啟用壓縮可以減少傳輸時間。

API Gateway 設定:

  1. 前往 API 設定
  2. 最小壓縮大小:設為 0(或適當值如 1024)
  3. 部署 API

Lambda 回應:

import gzip
import base64

def lambda_handler(event, context):
    # 檢查客戶端是否支援 gzip
    accept_encoding = event.get('headers', {}).get('accept-encoding', '')

    body = '{"data": "large response content..."}'

    if 'gzip' in accept_encoding:
        compressed = gzip.compress(body.encode())
        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json',
                'Content-Encoding': 'gzip'
            },
            'body': base64.b64encode(compressed).decode(),
            'isBase64Encoded': True
        }

    return {
        'statusCode': 200,
        'body': body
    }

快取設定

對於不常變動的資料,啟用 API Gateway 快取可以大幅減少 Lambda 呼叫次數。

REST API 快取設定:

  1. 前往階段設定
  2. 啟用 API 快取
  3. 選擇快取容量(0.5GB ~ 237GB)
  4. 設定 TTL(存活時間)

注意:快取需要額外費用(每小時 $0.02 起)。

如果你想用 Infrastructure as Code 管理這些設定,請參考 Terraform 部署 AWS Lambda 完整教學


常見錯誤處理

即使設定正確,還是可能遇到錯誤。

502 Bad Gateway

這是最常見的錯誤。

原因 1:回應格式錯誤

Lambda 必須回傳正確格式:

# 錯誤:直接回傳字串
return "Hello World"

# 正確:回傳指定格式
return {
    "statusCode": 200,
    "headers": {"Content-Type": "application/json"},
    "body": json.dumps({"message": "Hello World"})
}

原因 2:body 不是字串

# 錯誤:body 是 dict
return {
    "statusCode": 200,
    "body": {"message": "Hello"}  # 這會導致 502
}

# 正確:body 必須是字串
return {
    "statusCode": 200,
    "body": json.dumps({"message": "Hello"})
}

原因 3:Lambda 執行錯誤

檢查 CloudWatch Logs 找出實際錯誤訊息。

完整的錯誤處理指南,請參考 AWS Lambda 錯誤處理完整指南

CORS 問題

跨網域請求會遇到 CORS 錯誤。

解決方式 1:在 Lambda 回應中加入 CORS headers

return {
    "statusCode": 200,
    "headers": {
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
        "Access-Control-Allow-Headers": "Content-Type, Authorization"
    },
    "body": json.dumps(data)
}

解決方式 2:在 API Gateway 設定 CORS

HTTP API:

  1. 前往 API 設定 → CORS
  2. 設定 Access-Control-Allow-Origin
  3. 設定允許的 Methods 和 Headers

REST API:

  1. 選擇資源
  2. 點擊「啟用 CORS」
  3. 設定允許的來源和 headers

重點: OPTIONS 預檢請求也需要正確回應。

插圖 3:API Gateway CORS 設定介面

常見問題 FAQ

Lambda + API Gateway 的延遲大概多少?

正常情況下,API Gateway 增加約 10-30ms 延遲。加上 Lambda Cold Start(首次呼叫或閒置後),可能增加 100-500ms。使用 Provisioned Concurrency 或 SnapStart(Java)可以消除 Cold Start。

REST API 和 HTTP API 可以互相轉換嗎?

不能直接轉換,但可以遷移。建議新專案直接選擇 HTTP API(除非需要 REST API 特有功能),可以省下 70% 的 API Gateway 費用。

Lambda Authorizer 的快取時間怎麼設定?

在建立 Authorizer 時設定 TTL(0-3600 秒)。設為 0 表示不快取,每次請求都會呼叫 Authorizer。建議設定適當的快取時間(如 300 秒)以減少成本。

Function URL 可以綁定自訂網域嗎?

可以,但需要透過 CloudFront 設定。相較之下,API Gateway 的自訂網域設定更直接、更簡單。


結語:打造穩定的 Serverless API

Lambda + API Gateway 的組合已經被無數企業驗證。

從小型新創到大型企業,都在使用這個架構處理每天數百萬的 API 請求。

關鍵成功要素:

  1. 選擇正確的 API 類型:HTTP API 適合大多數場景
  2. 正確處理回應格式:避免 502 錯誤
  3. 實作適當的認證機制:保護你的 API
  4. 監控和優化:持續改善效能和成本

下一步建議:


API 架構需要專業規劃?

如果你正在:

  • 設計新的 API 架構
  • 評估 Lambda + API Gateway 的適用性
  • 優化現有 API 的效能與成本

預約架構諮詢,我們會在 24 小時內回覆你。

好的 API 架構能大幅降低維護成本。


參考資料

  1. AWS 官方文件:API Gateway Developer Guide
  2. AWS 官方文件:Lambda Proxy Integration
  3. AWS 官方文件:Lambda Authorizers
  4. AWS 官方文件:Lambda Function URLs
  5. AWS Blog:Choosing between REST APIs and HTTP APIs

需要專業的雲端建議?

無論您正在評估雲平台、優化現有架構,或尋找節費方案,我們都能提供協助

預約免費諮詢

相關文章