😎

CloudFront+S3で配信するに静的コンテンツにCloudFront Functionsでアレコレする

2023/08/11に公開

概要

前回の CloudFront+S3構成の静的ファイル配信をCDKだけで構築する の続き・発展系として、静的ファイルを配信する際に、CloudFront Functionsを使って、

  • requestに手を加える
  • responseに手を加える

をやっていく例を紹介したいと思います。
Cloudfront Functionsってどういう時に使うのか、CDKで実装するとどんな感じなのかなどの観点で参考になれば幸いです。

CloudFront Functionsとは

CloudFront Functionsの詳細な説明は公式や他のブログで詳しく説明されているので、詳細は割愛しますが、以下の特徴があります。

  • よりエッジ(Client)に近い場所で動作する
  • Viewer Request と Viewer Response の2種類のイベントタイプをサポート
    • リクエストを加工したい(例: リダイレクト) → Viewer Request
    • レスポンスを加工したい(例: 任意のheaderを付けたい) → Viewer Response
  • 合計パッケージサイズや処理時間に制限がある

参考: https://aws.amazon.com/jp/blogs/news/introducing-cloudfront-functions-run-your-code-at-the-edge-with-low-latency-at-any-scale/

Cloud Functionsの実装例

Viewer Response でHeaderを加工する

利用シーンの例:

  • JSONのファイルを配置して content-type = application/json として配信したいが、ファイルの拡張子を.jsonにできない場合
    • →json/huga というオブジェクトがあり、hugaの中身がjsonになっている
function handler(event) {
    var response = event.response;
    var headers = response.headers;

    // Set the content-type header
    headers['content-type'] = {value: 'application/json'};

    // Return response to viewers
    return response;
}

Viewer Request で任意のパスにリダイレクトさせる

利用シーン例:

  • ルートにないパスに置かれたHTMLファイルにhtml拡張子なしでアクセスしたい
      - → dir1/hellowworldというパスでアクセスして、dir1/hellowworld.htmlにリダイレクト
function handler(event) {
  try {
    var request = event.request;
    var host = request.headers.host.value;
    var uri = request.uri;

    // Check the URI is '/dir1'.
    if (uri === '/dir1/hellowworld') {
      var newurl = `https://${host}/dir1/hellowworld.html`
      var response = {
        statusCode: 301,
        statusDescription: 'Moved Permanently',
        headers:
          { "location": { "value": newurl } }
      }
      return response;
    } else {
      return request;
    }
  } catch (error) {
    console.error("An error occurred: ", error);
    var request = event.request;
    return request;
  }
}

※ GitHub上のコードではQueryParameterも引き継げるようにしています

CDKでの Cloud Functionsの実装

CloudFront Functionsの定義

    /**
     * Cloud Front Functions
     */
    const viewerRequestFunction = new cloudfront.Function(this, "viewerRequestFunction",
      {
        functionName: `viewerRequestFunction`,
        code: cloudfront.FunctionCode.fromFile({
          filePath: "./cloudfront_functions/viewer_request_function.js",
        }),
      }
    );
    const viewerResponseFunction = new cloudfront.Function(this, "viewerResponseFunction",
      {
        functionName: `viewerResponseFunction`,
        code: cloudfront.FunctionCode.fromFile({
          filePath: "./cloudfront_functions/viewer_response_function.js",
        }),
      }
    );

CloudFrontのDistributionにCloudFront Functionsを紐付ける

    // Cloudfront(distribution)
    const origin = new cloudfront_origins.S3Origin(bucket);
    const distribution = new cloudfront.Distribution(this, 'DistributionId', {
      defaultRootObject: 'index.html',
      defaultBehavior: {
        origin: origin,
        functionAssociations: [
          {
            eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
            function: viewerRequestFunction
          },
          {
            eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE,
            function: viewerResponseFunction
          }
        ]
    },
    });

まとめ

以上で、CloudFront+S3で配信するに静的コンテンツにCloudFront FunctionsでRequestやResponseを加工する例の紹介を終わります。

ソースコード全体はこちらにありますので参照ください。
https://github.com/kodai305/cdk-staticfile-deploy

CloudFront Functionsの利用リーンについてのイメージが湧いたり、導入する際の参考になれば幸いです。

Discussion