返回首頁AWS Lambda

Lambda@Edge 完整指南:CDN 邊緣運算應用與實戰

17 min 分鐘閱讀
#AWS Lambda#Lambda@Edge#CloudFront#CDN#邊緣運算#Serverless

Lambda@Edge 完整指南:CDN 邊緣運算應用與實戰

網站用了 CDN,全球用戶都能快速載入靜態檔案。但如果你需要在 CDN 層面做一些「動態處理」呢?

URL 重寫、A/B 測試、安全 Header 注入、圖片格式轉換——這些需求傳統上要經過 Origin Server 處理,延遲高且增加後端負擔。

Lambda@Edge 讓你在 CloudFront 的全球節點執行程式碼,把邏輯搬到離用戶最近的地方執行。

本文將完整解析 Lambda@Edge 的概念、限制與實戰應用。如果你還不熟悉 Lambda 基礎概念,建議先閱讀 AWS Lambda 完整指南


Lambda@Edge 是什麼

邊緣運算概念

邊緣運算(Edge Computing) 是將運算能力從中央伺服器移到靠近用戶的位置。

傳統架構:

用戶(台北)→ CloudFront Edge → Origin(東京)→ 處理邏輯 → 回傳
延遲:CDN 快取命中 ~20ms,未命中 ~200ms

Lambda@Edge 架構:

用戶(台北)→ CloudFront Edge → Lambda@Edge 處理 → 直接回傳
延遲:~50ms(不需要回 Origin)

與一般 Lambda 的差異

lambda-vs-lambda-edge-comparison 圖片說明:一般 Lambda 與 Lambda@Edge 的架構比較圖,顯示執行位置、觸發方式、限制等差異。

特性一般 LambdaLambda@Edge
執行位置單一 RegionCloudFront 全球 200+ 節點
部署區域任意 Region僅能在 us-east-1
觸發方式多種觸發器CloudFront Events
最長執行時間15 分鐘Viewer: 5 秒 / Origin: 30 秒
記憶體上限10 GB128 MB - 10 GB
環境變數支援不支援
VPC支援不支援
Container Image支援不支援

CloudFront 整合原理

Lambda@Edge 透過 CloudFront 的事件觸發。當請求到達 CloudFront 時,可以在 4 個不同的時機點執行 Lambda:

用戶請求 → Viewer Request → [快取檢查] → Origin Request → Origin
                                                              ↓
用戶 ← Viewer Response ← [快取] ← Origin Response ← Origin 回應

執行時機點

Viewer Request

觸發時機:CloudFront 收到用戶請求後,快取檢查前。

典型用途

  • URL 重寫(多語系路由)
  • A/B 測試分流
  • 請求驗證
  • 地理位置判斷
// Viewer Request 範例:根據語言重導向
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;

  // 取得 Accept-Language
  const acceptLanguage = headers['accept-language']?.[0]?.value || '';

  // 判斷語言並重寫 URI
  if (acceptLanguage.includes('zh')) {
    request.uri = '/zh' + request.uri;
  } else if (acceptLanguage.includes('ja')) {
    request.uri = '/ja' + request.uri;
  } else {
    request.uri = '/en' + request.uri;
  }

  return request;
};

Origin Request

觸發時機:快取未命中,轉發請求到 Origin 前。

典型用途

  • 動態選擇 Origin(藍綠部署)
  • 加入認證 Header
  • 修改請求參數
// Origin Request 範例:動態選擇 Origin
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;

  // 根據路徑選擇不同 Origin
  if (request.uri.startsWith('/api/v2')) {
    request.origin = {
      custom: {
        domainName: 'api-v2.example.com',
        port: 443,
        protocol: 'https',
        sslProtocols: ['TLSv1.2']
      }
    };
    request.headers['host'] = [{ key: 'host', value: 'api-v2.example.com' }];
  }

  return request;
};

Origin Response

觸發時機:收到 Origin 回應後,存入快取前。

典型用途

  • 加入安全 Header
  • 修改回應 Header
  • 壓縮或轉換內容

Viewer Response

觸發時機:回傳給用戶前(不論快取命中或未命中)。

典型用途

  • 加入 Cookie
  • 修改 Cache-Control Header
  • 移除敏感 Header

如何選擇正確的觸發點

lambda-edge-trigger-points-decision 圖片說明:Lambda@Edge 觸發點選擇決策樹,根據需求(修改請求/回應、快取影響)引導選擇正確的觸發時機。

需求建議觸發點原因
URL 重寫、A/B 測試Viewer Request快取檢查前處理
動態選擇 OriginOrigin Request快取未命中時才需要
加入安全 HeaderOrigin Response只處理一次,快取後自動帶
設定用戶 CookieViewer Response每次請求都要執行

效能考量:Viewer 觸發點每次請求都執行,Origin 觸發點只在快取未命中時執行。能用 Origin 就不要用 Viewer。


Lambda@Edge 限制

與一般 Lambda 的差異表

限制項目Lambda@Edge (Viewer)Lambda@Edge (Origin)一般 Lambda
執行時間5 秒30 秒15 分鐘
記憶體128 MB - 128 MB128 MB - 10 GB128 MB - 10 GB
部署套件1 MB50 MB250 MB
環境變數不支援不支援支援
VPC不支援不支援支援
Layers不支援不支援支援
Provisioned Concurrency不支援不支援支援

重要限制說明

1. 僅能在 us-east-1 部署

Lambda@Edge 函數必須在 N. Virginia (us-east-1) 建立,AWS 會自動複製到全球所有 CloudFront 節點。

# 錯誤:在其他 Region 建立會無法與 CloudFront 關聯
aws lambda create-function --region ap-northeast-1 ...  # 無法用於 Lambda@Edge

# 正確:必須在 us-east-1 建立
aws lambda create-function --region us-east-1 ...

2. 不支援環境變數

無法使用 process.env.MY_VAR。替代方案:

// 將設定寫在程式碼中
const CONFIG = {
  API_ENDPOINT: 'https://api.example.com',
  FEATURE_FLAG: true
};

// 或從 S3/Parameter Store 動態讀取(會增加延遲)

3. 不支援 VPC

Lambda@Edge 無法存取 VPC 內的資源。如果需要存取 RDS、ElastiCache,考慮:

  • 使用公開的 API Gateway 端點
  • 使用 DynamoDB(全球表)
  • 重新設計架構

CloudFront Functions vs Lambda@Edge

cloudfront-functions-vs-lambda-edge 圖片說明:CloudFront Functions 與 Lambda@Edge 的功能與適用場景比較表。

特性CloudFront FunctionsLambda@Edge
執行時間< 1 ms5-30 秒
記憶體2 MB128 MB - 10 GB
程式語言JavaScript (ES 5.1)Node.js, Python
網路存取不支援支援
費用~$0.10/百萬次~$0.60/百萬次
觸發點Viewer 階段全部 4 個

選擇建議

  • 簡單的 Header 操作、URL 重寫 → CloudFront Functions(更快更便宜)
  • 需要呼叫外部 API、複雜邏輯 → Lambda@Edge

不確定 Lambda@Edge 適不適合你?預約 CDN 評估,讓專家幫你分析。


實戰應用

應用一:URL 重寫(多語系、Pretty URL)

// 將 /blog/123 重寫為 /blog/123.html
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const uri = request.uri;

  // 如果是目錄路徑,加上 index.html
  if (uri.endsWith('/')) {
    request.uri += 'index.html';
  }
  // 如果沒有副檔名,加上 .html
  else if (!uri.includes('.')) {
    request.uri += '.html';
  }

  return request;
};

應用二:A/B 測試

// 依據 Cookie 進行 A/B 測試分流
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;

  // 檢查是否有 A/B 測試 Cookie
  let experimentGroup = 'A';
  const cookies = headers.cookie?.[0]?.value || '';
  const match = cookies.match(/ab-test=([AB])/);

  if (match) {
    experimentGroup = match[1];
  } else {
    // 新用戶隨機分配
    experimentGroup = Math.random() < 0.5 ? 'A' : 'B';
  }

  // 根據分組重寫路徑
  if (experimentGroup === 'B') {
    request.uri = '/experiment-b' + request.uri;
  }

  // 加入 Header 讓 Origin 知道分組
  request.headers['x-experiment-group'] = [{ key: 'X-Experiment-Group', value: experimentGroup }];

  return request;
};

應用三:安全 Header(CSP、HSTS)

// Origin Response:加入安全 Header
exports.handler = async (event) => {
  const response = event.Records[0].cf.response;
  const headers = response.headers;

  // Strict Transport Security
  headers['strict-transport-security'] = [{
    key: 'Strict-Transport-Security',
    value: 'max-age=31536000; includeSubDomains; preload'
  }];

  // Content Security Policy
  headers['content-security-policy'] = [{
    key: 'Content-Security-Policy',
    value: "default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com;"
  }];

  // X-Frame-Options
  headers['x-frame-options'] = [{
    key: 'X-Frame-Options',
    value: 'DENY'
  }];

  // X-Content-Type-Options
  headers['x-content-type-options'] = [{
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  }];

  return response;
};

應用四:圖片優化(WebP 轉換)

// Viewer Request:根據瀏覽器支援度重寫圖片路徑
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const uri = request.uri;

  // 檢查是否為圖片請求
  if (uri.match(/\.(jpe?g|png)$/i)) {
    // 檢查瀏覽器是否支援 WebP
    const accept = headers.accept?.[0]?.value || '';

    if (accept.includes('image/webp')) {
      // 重寫為 WebP 版本
      request.uri = uri.replace(/\.(jpe?g|png)$/i, '.webp');
    }
  }

  return request;
};

應用五:邊緣身份驗證

// Viewer Request:JWT Token 驗證
const jwt = require('jsonwebtoken');  // 需要打包進部署套件

const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`;

exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;

  // 取得 Authorization Header
  const authHeader = headers.authorization?.[0]?.value;

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return {
      status: '401',
      statusDescription: 'Unauthorized',
      headers: {
        'content-type': [{ key: 'Content-Type', value: 'application/json' }]
      },
      body: JSON.stringify({ error: 'Missing or invalid token' })
    };
  }

  const token = authHeader.substring(7);

  try {
    const decoded = jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] });

    // 將用戶資訊傳給 Origin
    request.headers['x-user-id'] = [{ key: 'X-User-Id', value: decoded.sub }];

    return request;
  } catch (err) {
    return {
      status: '401',
      statusDescription: 'Unauthorized',
      headers: {
        'content-type': [{ key: 'Content-Type', value: 'application/json' }]
      },
      body: JSON.stringify({ error: 'Invalid token' })
    };
  }
};

與 API Gateway 的身份驗證方式比較,請參考 API Gateway 身份驗證


部署教學

使用 AWS Console

Step 1:在 us-east-1 建立 Lambda 函數

  1. 前往 Lambda Console(確認在 N. Virginia)
  2. 建立函數 → Author from scratch
  3. Runtime:Node.js 20.x
  4. 貼上程式碼並部署

Step 2:發布版本

  1. Actions → Publish new version
  2. Lambda@Edge 需要版本號,不能用 $LATEST

Step 3:加入 CloudFront 觸發器

  1. 函數頁面 → Add trigger
  2. 選擇 CloudFront
  3. 選擇 Distribution 和觸發點
  4. 勾選「Deploy to Lambda@Edge」

使用 Terraform

詳細的 Terraform Lambda 部署基礎,請參考 Terraform 部署 Lambda 教學

# provider.tf - 必須在 us-east-1
provider "aws" {
  alias  = "us_east_1"
  region = "us-east-1"
}

# Lambda@Edge 函數
resource "aws_lambda_function" "edge" {
  provider = aws.us_east_1

  function_name = "my-edge-function"
  role          = aws_iam_role.edge_lambda.arn
  handler       = "index.handler"
  runtime       = "nodejs20.x"
  publish       = true  # 必須發布版本

  filename         = data.archive_file.edge_lambda.output_path
  source_code_hash = data.archive_file.edge_lambda.output_base64sha256
}

# IAM 角色
resource "aws_iam_role" "edge_lambda" {
  provider = aws.us_east_1
  name     = "edge-lambda-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = [
            "lambda.amazonaws.com",
            "edgelambda.amazonaws.com"  # Lambda@Edge 需要這個
          ]
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "edge_lambda_logs" {
  provider   = aws.us_east_1
  role       = aws_iam_role.edge_lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# CloudFront Distribution
resource "aws_cloudfront_distribution" "main" {
  # ... 其他設定 ...

  default_cache_behavior {
    # ... 其他設定 ...

    lambda_function_association {
      event_type   = "viewer-request"
      lambda_arn   = aws_lambda_function.edge.qualified_arn
      include_body = false
    }
  }
}

CDN 架構需要優化? Lambda@Edge、CloudFront Functions、邊緣快取各有適用場景。 預約 CDN 評估,讓我們幫你設計最佳 CDN 架構。


效能與成本

費用計算

Lambda@Edge 的計費方式:

計費項目單價
請求次數$0.60 / 百萬次(比一般 Lambda 貴 3 倍)
執行時間依記憶體,128 MB 約 $0.00000625 / 128ms

範例試算:每月 1000 萬次請求,平均執行 50ms,128 MB 記憶體

請求費用:10,000,000 × $0.0000006 = $6.00
執行時間:10,000,000 × 50ms × $0.00000625 / 128ms = $24.41
總計:約 $30.41 / 月

與一般 Lambda 成本比較

更詳細的 Lambda 費用計算,請參考 Lambda 費用計算詳解

場景Lambda@EdgeLambda + API Gateway
請求費用(每百萬)$0.60$0.20 + $1.00 = $1.20
全球延遲低(邊緣執行)較高(需回 Region)
適用情境簡單處理、低延遲需求複雜邏輯、需要 VPC

結論:如果邏輯簡單且對延遲敏感,Lambda@Edge 可能比 Lambda + API Gateway 更划算。

效能最佳化技巧

lambda-edge-optimization-tips 圖片說明:Lambda@Edge 效能最佳化要點,包含程式碼最小化、避免外部 API、善用快取等技巧。

1. 減少部署套件大小

# 使用 esbuild 或 webpack 打包,移除未使用的程式碼
npm install -D esbuild
esbuild index.js --bundle --minify --platform=node --outfile=dist/index.js

2. 避免不必要的外部 API 呼叫

// 不好:每次請求都呼叫外部 API
const response = await fetch('https://api.example.com/config');

// 較好:使用程式碼內的靜態設定,或快取結果
let cachedConfig = null;
let cacheTime = 0;

async function getConfig() {
  const now = Date.now();
  if (cachedConfig && now - cacheTime < 60000) {
    return cachedConfig;
  }
  cachedConfig = await fetch('https://api.example.com/config').then(r => r.json());
  cacheTime = now;
  return cachedConfig;
}

3. 善用 CloudFront 快取

在 Origin Response 加入 Header,讓結果被快取:

response.headers['cache-control'] = [{
  key: 'Cache-Control',
  value: 'public, max-age=86400'  // 快取 1 天
}];

常見問題 FAQ

Lambda@Edge 的 Log 在哪裡看?

Lambda@Edge 的 CloudWatch Logs 會寫入執行該函數的 Region,不是 us-east-1。台灣用戶的請求可能在東京(ap-northeast-1)或新加坡(ap-southeast-1)執行。你需要到各 Region 的 CloudWatch 查看,Log Group 名稱是 /aws/lambda/us-east-1.<function-name>

Lambda@Edge 可以使用 Node.js 以外的語言嗎?

可以,Lambda@Edge 支援 Node.js 和 Python。但 CloudFront Functions 只支援 JavaScript (ES 5.1)。如果你的邏輯很簡單,建議使用 CloudFront Functions,執行速度更快、費用更低。

更新 Lambda@Edge 需要多久生效?

Lambda@Edge 更新後,需要等待 CloudFront 將新版本傳播到全球節點,通常需要 5-15 分鐘。如果急需更新,可以考慮建立新的 CloudFront Distribution。

Lambda@Edge 可以讀取 Request Body 嗎?

可以,但需要特別設定。在 CloudFront Behavior 中勾選「Include Body」,且只支援 Viewer Request 和 Origin Request 觸發點。Body 大小限制是 40 KB(Viewer)或 1 MB(Origin)。


結語

Lambda@Edge 讓你在全球 CDN 節點執行程式碼,實現低延遲的動態處理。

本文重點回顧:

  • 4 個觸發點:Viewer Request/Response、Origin Request/Response,各有適用場景
  • 重要限制:僅能在 us-east-1 部署、不支援環境變數和 VPC
  • vs CloudFront Functions:簡單邏輯用 CF Functions,複雜邏輯用 Lambda@Edge
  • 實戰應用:URL 重寫、A/B 測試、安全 Header、圖片優化、邊緣驗證

適合使用 Lambda@Edge 的場景:

  • 需要在 CDN 層面處理請求/回應
  • 對全球用戶延遲敏感
  • 邏輯相對簡單,執行時間短

當 Lambda@Edge 遇到問題時,錯誤處理方式與一般 Lambda 略有不同,建議參考 Lambda 錯誤處理完整指南 了解基礎概念。

不適合的場景:

  • 需要存取 VPC 內資源
  • 執行時間超過 30 秒
  • 需要大量環境變數或 Layers

CDN 與邊緣運算需要專業規劃?

如果你正在:

  • 評估 Lambda@Edge 的適用場景
  • 優化網站的全球存取速度
  • 設計複雜的 CDN 邊緣邏輯

預約架構諮詢,我們會在 24 小時內回覆你。 正確的 CDN 架構能大幅提升用戶體驗與轉換率。


需要專業的雲端建議?

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

預約免費諮詢

相關文章