整合概念
AWS Lambda 與 API Gateway 的整合是建構無伺服器應用程式的核心架構。API Gateway 作為前端入口,接收來自客戶端的 HTTP 請求,並將這些請求轉發給 Lambda 函數處理,最後將回應返回給客戶端。
整合架構圖
1
2
3
| 客戶端 → API Gateway → Lambda 函數 → 後端服務(可選)
↑ ↓
←─────── 回應 ─────────←
|
整合類型
API Gateway 提供兩種主要的 Lambda 整合方式:
| 整合類型 | 說明 | 適用場景 |
|---|
| Lambda 代理整合 | API Gateway 將完整請求傳遞給 Lambda | 需要完整請求資訊時 |
| Lambda 自訂整合 | 可自訂請求/回應的映射模板 | 需要轉換資料格式時 |
整合優勢
- 完全無伺服器:無需管理任何基礎設施
- 自動擴展:根據請求量自動調整容量
- 成本效益:只為實際使用量付費
- 高可用性:內建多可用區支援
建立 REST API
步驟一:建立 API Gateway
- 登入 AWS 管理控制台
- 搜尋並進入 API Gateway 服務
- 點擊「建立 API」
- 選擇「REST API」(非私有)
- 點擊「建置」
步驟二:設定 API 基本資訊
1
2
3
| API 名稱:my-serverless-api
描述:我的無伺服器 API
端點類型:區域(Regional)
|
步驟三:建立資源
- 在「資源」面板中點擊「建立資源」
- 設定資源路徑:
1
2
| 資源名稱:users
資源路徑:/users
|
- 點擊「建立資源」
步驟四:建立方法
- 選擇剛建立的資源
- 點擊「建立方法」
- 選擇 HTTP 方法(例如:GET、POST)
1
2
3
4
| 方法類型:GET
整合類型:Lambda 函數
Lambda 代理整合:啟用
Lambda 函數:選擇您的函數
|
使用 AWS CLI 建立 API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 建立 REST API
aws apigateway create-rest-api \
--name "my-serverless-api" \
--description "我的無伺服器 API" \
--endpoint-configuration types=REGIONAL
# 取得 API ID 和根資源 ID
API_ID=$(aws apigateway get-rest-apis --query "items[?name=='my-serverless-api'].id" --output text)
ROOT_ID=$(aws apigateway get-resources --rest-api-id $API_ID --query "items[?path=='/'].id" --output text)
# 建立資源
aws apigateway create-resource \
--rest-api-id $API_ID \
--parent-id $ROOT_ID \
--path-part "users"
|
Lambda 代理整合
Lambda 代理整合是最常用的整合方式,它會將完整的 HTTP 請求資訊傳遞給 Lambda 函數。
請求格式
當使用 Lambda 代理整合時,Lambda 函數會收到以下格式的事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| {
"resource": "/users",
"path": "/users",
"httpMethod": "GET",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"queryStringParameters": {
"id": "123"
},
"pathParameters": {
"userId": "456"
},
"body": "{\"name\": \"John\"}",
"isBase64Encoded": false,
"requestContext": {
"accountId": "123456789012",
"apiId": "abcdef1234",
"stage": "prod",
"requestId": "request-id",
"identity": {
"sourceIp": "192.168.1.1"
}
}
}
|
回應格式
Lambda 函數必須返回符合以下格式的回應:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| import json
def lambda_handler(event, context):
# 處理請求邏輯
users = [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
"body": json.dumps({
"message": "成功",
"data": users
})
}
|
處理不同 HTTP 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| import json
def lambda_handler(event, context):
http_method = event['httpMethod']
if http_method == 'GET':
return handle_get(event)
elif http_method == 'POST':
return handle_post(event)
elif http_method == 'PUT':
return handle_put(event)
elif http_method == 'DELETE':
return handle_delete(event)
else:
return {
"statusCode": 405,
"body": json.dumps({"error": "方法不允許"})
}
def handle_get(event):
# 處理 GET 請求
query_params = event.get('queryStringParameters', {}) or {}
user_id = query_params.get('id')
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"userId": user_id})
}
def handle_post(event):
# 處理 POST 請求
body = json.loads(event.get('body', '{}'))
return {
"statusCode": 201,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"message": "資源已建立", "data": body})
}
def handle_put(event):
# 處理 PUT 請求
return {
"statusCode": 200,
"body": json.dumps({"message": "資源已更新"})
}
def handle_delete(event):
# 處理 DELETE 請求
return {
"statusCode": 204,
"body": ""
}
|
處理路徑參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import json
def lambda_handler(event, context):
# 取得路徑參數
path_parameters = event.get('pathParameters', {}) or {}
user_id = path_parameters.get('userId')
if not user_id:
return {
"statusCode": 400,
"body": json.dumps({"error": "缺少 userId 參數"})
}
# 根據 userId 查詢使用者
user = get_user_by_id(user_id)
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(user)
}
|
部署階段
API Gateway 使用「階段」(Stage)來管理 API 的不同版本和環境。
建立部署
- 在 API Gateway 控制台中選擇您的 API
- 點擊「部署 API」
- 選擇或建立新的階段
常見階段規劃
| 階段 | 用途 | 說明 |
|---|
| dev | 開發環境 | 開發人員測試用 |
| staging | 預備環境 | 上線前最終測試 |
| prod | 生產環境 | 對外服務 |
使用 AWS CLI 部署
1
2
3
4
5
6
7
8
9
10
| # 建立部署
aws apigateway create-deployment \
--rest-api-id $API_ID \
--stage-name prod \
--description "生產環境部署"
# 取得階段資訊
aws apigateway get-stage \
--rest-api-id $API_ID \
--stage-name prod
|
階段變數
階段變數可用於在不同環境中設定不同的參數:
1
2
3
4
5
| # 設定階段變數
aws apigateway update-stage \
--rest-api-id $API_ID \
--stage-name prod \
--patch-operations op=replace,path=/variables/lambdaAlias,value=PROD
|
在 Lambda 整合中使用階段變數:
1
| Lambda 函數 ARN:arn:aws:lambda:region:account:function:myFunction:${stageVariables.lambdaAlias}
|
取得 API 端點
部署後,您可以取得 API 的調用 URL:
1
| https://{api-id}.execute-api.{region}.amazonaws.com/{stage}/
|
例如:
1
| https://abcdef1234.execute-api.ap-northeast-1.amazonaws.com/prod/users
|
節流設定
可以在階段層級設定請求節流:
1
2
3
4
5
6
| aws apigateway update-stage \
--rest-api-id $API_ID \
--stage-name prod \
--patch-operations \
op=replace,path=/throttling/rateLimit,value=1000 \
op=replace,path=/throttling/burstLimit,value=500
|
CORS 設定
跨來源資源共用(CORS)是瀏覽器安全機制,當您的前端應用程式需要呼叫不同網域的 API 時,必須正確設定 CORS。
啟用 CORS 的步驟
方法一:使用控制台啟用
- 在 API Gateway 控制台中選擇資源
- 點擊「啟用 CORS」
- 設定 CORS 選項:
1
2
3
| Access-Control-Allow-Origin:*
Access-Control-Allow-Headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,OPTIONS
|
- 點擊「儲存」
方法二:手動設定 OPTIONS 方法
- 為資源建立 OPTIONS 方法
- 整合類型選擇「Mock」
- 在方法回應中設定標頭
1
2
3
4
5
| 狀態碼:200
回應標頭:
- Access-Control-Allow-Headers
- Access-Control-Allow-Methods
- Access-Control-Allow-Origin
|
Lambda 函數中的 CORS 標頭
在 Lambda 代理整合中,您需要在回應中包含 CORS 標頭:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| import json
def lambda_handler(event, context):
# CORS 標頭
cors_headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS"
}
# 處理 OPTIONS 預檢請求
if event['httpMethod'] == 'OPTIONS':
return {
"statusCode": 200,
"headers": cors_headers,
"body": ""
}
# 處理實際請求
try:
result = process_request(event)
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
**cors_headers
},
"body": json.dumps(result)
}
except Exception as e:
return {
"statusCode": 500,
"headers": cors_headers,
"body": json.dumps({"error": str(e)})
}
|
限制特定網域
在生產環境中,建議限制允許的來源網域:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| ALLOWED_ORIGINS = [
"https://example.com",
"https://www.example.com",
"https://app.example.com"
]
def get_cors_headers(event):
origin = event.get('headers', {}).get('origin', '')
if origin in ALLOWED_ORIGINS:
return {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers": "Content-Type,Authorization",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS"
}
return {}
|
使用 AWS SAM 設定 CORS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Api:
Cors:
AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,Authorization'"
AllowOrigin: "'*'"
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowMethods: "'*'"
AllowHeaders: "'*'"
AllowOrigin: "'*'"
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.lambda_handler
Runtime: python3.11
Events:
ApiEvent:
Type: Api
Properties:
Path: /users
Method: GET
RestApiId: !Ref MyApi
|
最佳實踐
1. 安全性設定
- 使用 IAM 角色或 Lambda 授權方進行身份驗證
- 設定 API 金鑰和使用計畫
- 啟用 AWS WAF 保護 API
2. 效能優化
- 使用 API Gateway 快取減少 Lambda 調用
- 適當設定 Lambda 記憶體和逾時
- 考慮使用 Provisioned Concurrency
3. 監控與日誌
- 啟用 CloudWatch Logs 進行除錯
- 設定 X-Ray 追蹤請求路徑
- 建立 CloudWatch 警示監控錯誤率
4. 版本控制
- 使用 API Gateway 階段管理不同環境
- Lambda 函數使用版本和別名
- 實作藍綠部署策略
結論
AWS Lambda 與 API Gateway 的整合提供了強大且靈活的無伺服器 API 解決方案。透過正確設定 REST API、Lambda 代理整合、部署階段和 CORS,您可以建構高效能、可擴展且安全的 API 服務。掌握這些核心概念後,您將能夠快速開發和部署各種無伺服器應用程式。