概述
國內 Amazon Cloudfront 目前不支援 Lambda@edge 功能,不能實現基於 CDN 的 A/B 測試、rewrite、redirect、token 認證和產生 response 等功能,本文介紹如何利用 API Gateway 和 Lambda 實現 Lambda@edge 的功能。下面實驗介紹透過 request header 引數值,實現 redirect 和 rewrite 的測試場景,根據 header(test_version)引數值,回源到指定目錄的檔案,根據 header(redirect)引數值,返回 302 重定向地址。
亞馬遜雲科技開發者社群為開發者們提供全球的開發技術資源。這裡有技術文件、開發案例、技術專欄、培訓影片、活動與競賽等。幫助中國開發者對接世界最前沿技術,觀點,和專案,並將中國優秀開發者或技術推薦給全球雲社群。如果你還沒有關注/收藏,看到這裡請一定不要匆匆劃過,點這裡讓它成為你的技術寶庫! |
整體實驗的架構圖如下:
架構圖說明:
- Cloudfront 是 Amazon 的 CDN 服務,可以設定源站域名,回源 header,快取策略等。
- API Gateway 有兩種型別可以支援 rewrite 和 redirect 測試場景,實驗中採用 HTTP API,考慮到成本更低,同時不需要 Rest API 的高階功能。
- Lambda 實現了 rewrite 和 redirect 的測試程式碼,支援驗證 security header。支援多種主流語言,實驗中採用 Python3.9 語言實現。
- S3 儲存測試的 html 和 png 檔案。
詳細步驟說明
1.新建 S3 Bucket
比如:bucket name:lambda-api-2022
上傳檔案列表:
index.html – 歡迎頁
v1/test.html – A 測試頁
v1/test.png – A 測試圖片
v2/test.html – B 測試頁
v2/test.png – B 測試圖片
2.新建 Lambda 程式
1)新建 IAM Role,執行 Lambda 程式,比如 Role name:RoleForLambda
需要的許可權如下:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": " s3get",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::lambda-api-2022/*"
},
{
"Sid": " putlogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
2)建立 Lambda 程式
採用下列的引數和配置:
Function name:lambdaapi
Runtime:Python 3.9
Execution role:RoleForLambda(上一步建立的)
修改 Configuration 的配置:
新增 Environment variables
新增 Key=bucket,Value=lambda-api-2022
新增 Key=lambda_auth,Value=lambdaapi_test
新增 Key=redirect_path,Value=https://xxx.cloudfront.net,value 來自下面建立的 Cloudfront distribution
General configuration
修改 Timeout 為20秒
Lambda Source Code:
import boto3
import base64
import os
s3_client = boto3.client('s3')
def lambda_handler(event, context):
print(event)
# check security header
if 'lambda_auth' in event['headers'] and event['headers']['lambda_auth'] == os.environ['lambda_auth']:
bucket = os.environ['bucket']
key = event['rawPath'][1:] # request URI
print(key)
if len(key) == 0:
key = 'index.html'
# rewrite url
if 'test_version' in event['headers']:
key = event['headers']['test_version']+'/'+key
# redirect
if 'redirect' in event['headers'] and event['headers']['redirect'] == 'true':
return {
'statusCode': 302,
'statusDescription': 'Found',
'headers': { 'Location': os.environ['redirect_path'] + '/' + key }
}
# return content body - rewrite
try:
response = s3_client.get_object(Bucket = bucket, Key = key)
responseBody = response['Body'].read() # return bytes from S3
responseContentType = response['ResponseMetadata']['HTTPHeaders']['content-type']
return {
'headers': { "Content-Type": responseContentType },
'statusCode': 200,
'body': base64.b64encode(responseBody).decode('utf-8'),
'isBase64Encoded': True
}
except Exception as e:
print('error message - ', e.__class__.__name__, ' : ', e)
return {
'statusCode': 200,
'body': 'no file: '+key
}
else:
# auth failed
return {
'statusCode': 403,
'body': 'request is forbidden'
}
Lambda Source Code 說明:
在 Cloudfront 回源時,新增 lambda_auth header,用於 Lambda 認證請求,當認證失敗時,返回 403 錯誤。
當請求根目錄時,返回 index.html
當 request header 包含 test_version 時,轉向到指定目錄下的檔案。
將返回的 body 透過 base64 編碼,以支援 binary 物件。
當 request header 包含 redirect=true 時,返回 302 重定向資訊。
3.新建 API Gateway
在 API Gateway 中,新建 HTTP API,比如 API Name:lambdaapi
新建 Lambda integration,選擇上一步建立的 Lambda(lambdaapi)
在 Configure routes 時,Resource path 設定為 “/{proxy+}”
在 Deploy Stages中,找到 $default stage 的 Invoke URL,如https://xxx.execute-api.xxx.amazonaws.com,此為 API Gateway 的請求地址。
測試 API gateway:
- 測試 security header
測試命令:curl https://xxx.execute-api.xxx.amazonaws.com?trk=cndc-detail
返回結果:request is forbidden
- 測試訪問根路徑,傳入 lambda_auth header
測試命令:curl -v -H “lambda_auth:lambdaapi_test” https://xxx.execute-api.xxx.amazonaws.com?trk=cndc-detail
返回結果:statusCode=200
- 訪問 B 測試頁,傳入 lambda_auth header和test_version header
測試命令:curl -H “lambda_auth:lambdaapi_test” -H “test_version:v2” https://xxx.execute-api.xxx.amazonaws.com/test.html?trk=cndc-...
返回 v2/test.html 的內容
- 訪問B測試圖片,傳入 lambda_auth header 和 test_version header
測試命令:curl -H “lambda_auth:lambdaapi_test” -H “test_version:v2” https://xxx.execute-api.xxx.amazonaws.com/test.png?trk=cndc-d... > test.png
將 response 儲存為 test.png 圖片。
- 測試 redirect,傳入 redirect header
測試命令:curl -v -H “lambda_auth:lambdaapi_test” -H “test_version:v1” -H “redirect:true” https://xxx.execute-api.xxx.amazonaws.com/test.html
返回 302 重定向資訊
4.配置 Cloudfront
1)建立 Origin request policy,Amazon Cloud Global支援該功能
在 Cloudfront Policies 中,新建 origin request policy,例如 Name:lambdaapi
配置如下:
Headers:選擇 Include the following headers,並手工新增 header:test_version和redirect
Query strings: All
2)建立 Cloudfront Distribution
在 Cloudfront 中,新建 Distribution,例如 Description:lambdaapi
配置如下:
Origin domain:xxx.execute-api.xxx.amazonaws.com,上面建立的 HTTP API 域名
Protocol:HTTPS only
Add custom header:
Header name = lambda_auth,Value = lambdaapi_test
在 Amazon Cloud Global,支援 Cache policy and origin request policy (recommended),配置下面兩個引數:
Cache policy:CachingDisabled
Origin request policy:Custom lambdaapi
或者在 Amazon Cloud China,支援 Legacy cache settings,配置下面 3 個引數:
Headers:選擇 Include the following headers,並手工新增header:test_version和redirect。
Query strings: All
Cookies:All
如果不需要 Cloudfront 快取內容時,需要設定 Object caching 為Customize,同時將 Minimum TTL、Maximum TTL 和 Default TTL 都設為 0.
注:需新建 origin 和 behavior,配合 redirect 後 Cloudfront 地址。
5.測試 Cloudfront
1.在 Cloudfront Distributions (Lambdaapi)的 General Details 中,找到 Distribution domain name,例如 cloudfront.net
2.訪問 A 測試頁,傳入 test_version header
測試命令:curl -H “test_version:v1” https://xxx.cloudfront.net/test.html?trk=cndc-detail
返回 v1/test.html 的內容
3.測試 redirect,傳入 test_version 和 redirect header
測試命令:curl -I -H “test_version:v1” -H “redirect:true” https://xxx.cloudfront.net/test.html?trk=cndc-detail
返回 302 重定向的內容
結論
在這篇文章中,介紹瞭如何利用 API Gateway 和 Lambda 處理Cloudfront 的內容請求,實現 Lambda@edge 的功能,在實驗中,介紹了 Amazon S3、Lambda、API Gateway 和 Cloudfront 的配置方法,實現了 rewrite 和 redirect 的測試場景。
參考資料
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/GetStar...
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_cre...
- https://docs.aws.amazon.com/lambda/latest/dg/getting-started....
- https://docs.aws.amazon.com/apigateway/latest/developerguide/...
- https://docs.aws.amazon.com/AmazonCloudFront/latest/Developer...
- https://docs.aws.amazon.com/AmazonCloudFront/latest/Developer...
本篇作者
薛召兵
Amazon 解決方案架構師,負責幫助客戶進行上雲架構的設計和諮詢。同時致力於 Amazon 容器服務、媒體服務和機器學習服務在國內和全球商業客戶的應用和推廣,推進企業服務遷移上雲程式。有 10 年以上的軟體開發、售前技術支援、系統架構設計等經驗。
文章來源:https://dev.amazoncloud.cn/column/article/6309c985d4155422a46...