S 3 WebアプリとAPIゲートウェイのための単一のCloudfront配布
33256 ワード
このポストは、シングルを使う方法を概説しますAmazon CloudFront あなたのウェブアプリの配布は、S 3とあなたのバックエンドAPIでホストされます.
私が達成したい結果は: 私は使用されますAmazon API GatewayV2 この例のための私のバックエンドとして、原則は他のバックエンドに適用すべきです.
Why Summary Architecture
Step by Step Tutorial Using CDK CDK Setup API Gateway with a Lambda Backend S3 Bucket and CloudFront Distribution Add API Gateway as Another CloudFront Origin Lambda@Edge for Handling Redirects Test It Out Key Take Aways Alternatives なぜ
使用してCloudFrontは、パスパターンに基づいて複数の起源から提供する CloudFrontは、あなたのAPIパスがクラウドフロントで設定されたものと同じであることを確認します デフォルトではCloudfrontはあなたのAPIにどんなヘッダも転送しないので、どのヘッダが転送されるのかを明示的にします APIエラー応答を上書きするので、CloudFrontカスタムエラー構成を使用しないでください 用途Lambda@EdgeS 3から404 NosuchKeyエラーをリダイレクトする 代替案
リダイレクトのための第3の起源として公開S 3バケット静的ウェブサイトを使用してください あなたのAPIゲートウェイまたはALB これが役に立つという望み!
以下のコメント欄でのフィードバックと質問歓迎
私が達成したい結果は:
website.com
私のWebアプリをロードしますwebsite.com/non-existent-page
私は人間のフレンドリー404ページを与えるwebsite.com/api/*
バックエンドAPIにルーティングされます.website.com/api/non-existent-endpoint
私のバックエンドと私の人間に優しい404ページからのマシンフレンドリーなエラー応答を返す目次
Step by Step Tutorial Using CDK
なぜ
私が両方のために別々の配布を使うことができるとき、なぜ私のウェブアプリとAPIのために一つのCloudfront配布を使用しますか?例えば、私はちょうど使用することができませんwebsite.com
and api.website.com
?
要するに、サブドメインは管理するのが難しくありえます、そして、若干の組織で、それは新しいサブドメインを要求するのさえ難しいかもしれません.
サブドメイン管理が困難になる例は、異なる環境です.以下のサブドメインを持つdev環境があるとしましょうdev.website.com
; あなたのAPIはapi.dev.website.com
または、dev.api.website.com
? 別のSSL証明書を作成しますか?あなたのコルズのルールは?CSPはどうですか?どのようにあなたのコードベースでこれを管理するつもりですか?
...そして、私は永遠に行くことができます.
それで、一部の人々は、ちょうど使用を考慮するかもしれません/api/
そして、それを一日呼ぶ.このポストはそれらの人々のためです.
概要
基本的に、我々は、経路パターンに基づいて複数の起源からCloudfrontサービスを提供します.この場合、私たちは前方にCloudfrontを持ちます/api/*
APIゲートウェイへのリクエストと他のすべてのリクエストをs 3に転送します.これだけで結果1、3、4を達成する.
しかし、誰かがアクセスしようとするなら/non-existent-page
あなたは私たちの人間に優しい404エラーではないS 3から“nosuchkey”エラーを取得します.
CloudFrontカスタムエラー構成を使用して、すべての404エラーをインデックスに上書きする方法について説明します.HTMLまたは専用の404ページ?残念なことに、CloudFrontは、今日の起源ごとのカスタムエラー設定を設定する機能を持っていないので、この場合、バックエンドAPIエラー応答を上書きします(基本的に、ここで解決しようとしている問題のコアです).
それで、質問のカスタムエラー構成で、我々は残ります.
ええと、Lambda@edge.
私たちはLambda@Edge for /non-existent-page
あなたのS 3の起源へのルートは、我々のインデックスに戻って404応答をリダイレクト.HTMLまたは専用の404ページに.
建築
かなりまっすぐ前方に、私たちはLambda@Edge我々のS 3起源と我々の配布の間で.
CDKを使用してステップバイステップチュートリアル
以下は、CDKを使用して作業例を構築するステップバイステップチュートリアルです.
参考のために、ローカルにインストールしたものです.
$ node --version
v14.13.1
$ yarn --version # you can use npm
1.22.5
$ cdk --version
1.67.0 (build 2b4dd71)
$ docker --version # used by CDK to compile typescript lambdas
Docker version 19.03.13, build 4484c46d9d
すべてのソースコードをここで見つけることもできます.
EVNZ
/
ブログCFシングル配布
S 3バケツとAPIゲートウェイバックエンドでホストされるあなたのウェブアプリのための一つのアマゾンCloudfront配布の例
CDKセットアップ
タイプスクリプトCDKプロジェクトを作成し、いくつかの依存関係をインストールしましょう.
$ cdk init app --language typescript
...
$ yarn add \
@aws-cdk/aws-cloudfront \
@aws-cdk/aws-apigatewayv2 \
@aws-cdk/aws-s3 \
@aws-cdk/aws-s3-deployment \
@aws-cdk/aws-lambda \
@aws-cdk/aws-lambda-nodejs \
@aws-cdk/aws-iam
...
$ yarn add --dev --exact [email protected] # for compiling typescript lambdas
ラムダバックエンドを持つAPIゲートウェイ
あなたのCDKアプリのlibフォルダの中にbackend
とダミーのラムダ関数を設定します(index.ts
) これは200を返します:
export const handler = async (event: any): Promise<any> => {
return {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ key: "Machine friendly hello world" }),
};
};
必要なインポートを追加lib/{your-stack-name}.ts
ファイル
import * as cdk from "@aws-cdk/core";
import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
import { Runtime } from "@aws-cdk/aws-lambda";
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
ここでは、CDKスタックに次のコードを追加してラムダ関数を作成し、API GateWavv 2と統合できます.
const httpApi = new apigatewayv2.HttpApi(this, "MyApiGateway");
const helloWorldLambda = new NodejsFunction(this, "HelloWorldLambda", {
entry: `${__dirname}/backend/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
const lambdaIntegration = new apigatewayv2.LambdaProxyIntegration({
handler: helloWorldLambda,
});
httpApi.addRoutes({
path: "/api/helloworld", // You must include the `/api/` since CloudFront will not truncate it
methods: [apigatewayv2.HttpMethod.GET],
integration: lambdaIntegration,
});
3 . S 3バケットとクラウドフロントディストリビューション
あなたのCDKアプリのlibフォルダの中にfrontend
で、index.html
いくつかのHTMLコンテンツでファイルを
<html>
<body>
Hello world
</body>
</html>
以下のCDK依存関係をインポートしますlib/{your-stack-name}.ts
ファイル
import * as cloudfront from "@aws-cdk/aws-cloudfront";
import * as s3 from "@aws-cdk/aws-s3";
import * as iam from "@aws-cdk/aws-iam";
import { Duration } from "@aws-cdk/core";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";
今、プライベートのS 3のバケツを使用して標準的な静的なウェブサイトを作成することができますCloudfrontの配布とすべての間(iams、オアシスなど).
const cloudfrontOAI = new cloudfront.OriginAccessIdentity(
this,
"cloudfrontOAI",
{
comment: `Allows CloudFront access to S3 bucket`,
}
);
const websiteBucket = new s3.Bucket(this, "S3BucketForWebsiteContent", {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
cors: [
{
allowedOrigins: ["*"],
allowedMethods: [s3.HttpMethods.GET],
maxAge: 3000,
},
],
});
// uploads index.html to s3 bucket
new s3deploy.BucketDeployment(this, "DeployWebsite", {
sources: [s3deploy.Source.asset(`${__dirname}/frontend`)], // folder containing your html files
destinationBucket: websiteBucket,
});
websiteBucket.addToResourcePolicy(
new iam.PolicyStatement({
sid: "Grant Cloudfront Origin Access Identity access to S3 bucket",
actions: ["s3:GetObject"],
resources: [websiteBucket.bucketArn + "/*"],
principals: [cloudfrontOAI.grantPrincipal],
})
);
const cloudfrontDistribution = new cloudfront.CloudFrontWebDistribution(
this,
"MyDistribution",
{
comment: "CDN for Web App",
defaultRootObject: "index.html",
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
originConfigs: [
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
],
}
);
別のCloudfront起源としてAPIゲートウェイを加えてください
APIゲートウェイを別の起源として追加する/api/*
CloudFrontディストリビューション(APIゲートウェイの原点がS 3の原点より上にあることを確認してください)/api/*
先読みをする)
originConfigs: [
{
// make sure your backend origin is first in the originConfigs list so it takes precedence over the S3 origin
customOriginSource: {
domainName: `${httpApi.httpApiId}.execute-api.${this.region}.amazonaws.com`,
},
behaviors: [
{
pathPattern: "/api/*", // CloudFront will forward `/api/*` to the backend so make sure all your routes are prepended with `/api/`
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: Duration.seconds(0),
forwardedValues: {
queryString: true,
headers: ["Authorization"], // By default CloudFront will not forward any headers through so if your API needs authentication make sure you forward auth headers across
},
},
],
},
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
];
ハンドリングリダイレクトのためのラムダエッジ
注意:一旦作成したらLambda@Edge削除するには時間がかかる.
あなたのCDKアプリのlibフォルダの中にredirect
で、index.ts
以下の内容でファイルをインクルードしますLambda@Edge):
"use strict";
exports.handler = (event: any, context: any, callback: any) => {
const response = event.Records[0].cf.response;
const request = event.Records[0].cf.request;
/**
* This function updates the HTTP status code in the response to 302, to redirect to another
* path (cache behavior) that has a different origin configured. Note the following:
* 1. The function is triggered in an origin response
* 2. The response status from the origin server is an error status code (4xx or 5xx)
*/
if (response.status == 404) {
const redirect_path = `/`; //redirects back to root so to index.html
response.status = 302;
response.statusDescription = "Found";
/* Drop the body, as it is not required for redirects */
response.body = "";
response.headers["location"] = [{ key: "Location", value: redirect_path }];
}
callback(null, response);
};
今、あなたのCDKにラムダリソースを追加します(後でこの分布の中でラムダを参照するときに、これがクラウドフロントディストリビューションリソースの前にあることを確認してください):
const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
最後にこれを関連付けるLambda@EdgeS 3の起源で
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
lambdaFunctionAssociations: [
{
lambdaFunction: redirectLambda.currentVersion,
eventType: LambdaEdgeEventType.ORIGIN_RESPONSE,
},
],
},
],
},
テストする
次のエンドポイントを訪問してください/
こんにちは世界インデックスを返します.HTMLページ
/api/helloworld
マシンフレンドリーメッセージを返す必要があります
/api/non-existent-endpoint
バックエンドAPI
そしてついに/non-existent-page
我々のインデックスに我々をリダイレクトしなければなりません.我々はWebアプリの中でそれを処理することができますので、HTML
キーテイク
基本的に、我々は、経路パターンに基づいて複数の起源からCloudfrontサービスを提供します.この場合、私たちは前方にCloudfrontを持ちます
/api/*
APIゲートウェイへのリクエストと他のすべてのリクエストをs 3に転送します.これだけで結果1、3、4を達成する.しかし、誰かがアクセスしようとするなら
/non-existent-page
あなたは私たちの人間に優しい404エラーではないS 3から“nosuchkey”エラーを取得します.CloudFrontカスタムエラー構成を使用して、すべての404エラーをインデックスに上書きする方法について説明します.HTMLまたは専用の404ページ?残念なことに、CloudFrontは、今日の起源ごとのカスタムエラー設定を設定する機能を持っていないので、この場合、バックエンドAPIエラー応答を上書きします(基本的に、ここで解決しようとしている問題のコアです).
それで、質問のカスタムエラー構成で、我々は残ります.
ええと、Lambda@edge.
私たちはLambda@Edge for
/non-existent-page
あなたのS 3の起源へのルートは、我々のインデックスに戻って404応答をリダイレクト.HTMLまたは専用の404ページに.建築
かなりまっすぐ前方に、私たちはLambda@Edge我々のS 3起源と我々の配布の間で.
CDKを使用してステップバイステップチュートリアル
以下は、CDKを使用して作業例を構築するステップバイステップチュートリアルです.
参考のために、ローカルにインストールしたものです.
$ node --version
v14.13.1
$ yarn --version # you can use npm
1.22.5
$ cdk --version
1.67.0 (build 2b4dd71)
$ docker --version # used by CDK to compile typescript lambdas
Docker version 19.03.13, build 4484c46d9d
すべてのソースコードをここで見つけることもできます.
EVNZ
/
ブログCFシングル配布
S 3バケツとAPIゲートウェイバックエンドでホストされるあなたのウェブアプリのための一つのアマゾンCloudfront配布の例
CDKセットアップ
タイプスクリプトCDKプロジェクトを作成し、いくつかの依存関係をインストールしましょう.
$ cdk init app --language typescript
...
$ yarn add \
@aws-cdk/aws-cloudfront \
@aws-cdk/aws-apigatewayv2 \
@aws-cdk/aws-s3 \
@aws-cdk/aws-s3-deployment \
@aws-cdk/aws-lambda \
@aws-cdk/aws-lambda-nodejs \
@aws-cdk/aws-iam
...
$ yarn add --dev --exact [email protected] # for compiling typescript lambdas
ラムダバックエンドを持つAPIゲートウェイ
あなたのCDKアプリのlibフォルダの中にbackend
とダミーのラムダ関数を設定します(index.ts
) これは200を返します:
export const handler = async (event: any): Promise<any> => {
return {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ key: "Machine friendly hello world" }),
};
};
必要なインポートを追加lib/{your-stack-name}.ts
ファイル
import * as cdk from "@aws-cdk/core";
import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
import { Runtime } from "@aws-cdk/aws-lambda";
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
ここでは、CDKスタックに次のコードを追加してラムダ関数を作成し、API GateWavv 2と統合できます.
const httpApi = new apigatewayv2.HttpApi(this, "MyApiGateway");
const helloWorldLambda = new NodejsFunction(this, "HelloWorldLambda", {
entry: `${__dirname}/backend/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
const lambdaIntegration = new apigatewayv2.LambdaProxyIntegration({
handler: helloWorldLambda,
});
httpApi.addRoutes({
path: "/api/helloworld", // You must include the `/api/` since CloudFront will not truncate it
methods: [apigatewayv2.HttpMethod.GET],
integration: lambdaIntegration,
});
3 . S 3バケットとクラウドフロントディストリビューション
あなたのCDKアプリのlibフォルダの中にfrontend
で、index.html
いくつかのHTMLコンテンツでファイルを
<html>
<body>
Hello world
</body>
</html>
以下のCDK依存関係をインポートしますlib/{your-stack-name}.ts
ファイル
import * as cloudfront from "@aws-cdk/aws-cloudfront";
import * as s3 from "@aws-cdk/aws-s3";
import * as iam from "@aws-cdk/aws-iam";
import { Duration } from "@aws-cdk/core";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";
今、プライベートのS 3のバケツを使用して標準的な静的なウェブサイトを作成することができますCloudfrontの配布とすべての間(iams、オアシスなど).
const cloudfrontOAI = new cloudfront.OriginAccessIdentity(
this,
"cloudfrontOAI",
{
comment: `Allows CloudFront access to S3 bucket`,
}
);
const websiteBucket = new s3.Bucket(this, "S3BucketForWebsiteContent", {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
cors: [
{
allowedOrigins: ["*"],
allowedMethods: [s3.HttpMethods.GET],
maxAge: 3000,
},
],
});
// uploads index.html to s3 bucket
new s3deploy.BucketDeployment(this, "DeployWebsite", {
sources: [s3deploy.Source.asset(`${__dirname}/frontend`)], // folder containing your html files
destinationBucket: websiteBucket,
});
websiteBucket.addToResourcePolicy(
new iam.PolicyStatement({
sid: "Grant Cloudfront Origin Access Identity access to S3 bucket",
actions: ["s3:GetObject"],
resources: [websiteBucket.bucketArn + "/*"],
principals: [cloudfrontOAI.grantPrincipal],
})
);
const cloudfrontDistribution = new cloudfront.CloudFrontWebDistribution(
this,
"MyDistribution",
{
comment: "CDN for Web App",
defaultRootObject: "index.html",
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
originConfigs: [
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
],
}
);
別のCloudfront起源としてAPIゲートウェイを加えてください
APIゲートウェイを別の起源として追加する/api/*
CloudFrontディストリビューション(APIゲートウェイの原点がS 3の原点より上にあることを確認してください)/api/*
先読みをする)
originConfigs: [
{
// make sure your backend origin is first in the originConfigs list so it takes precedence over the S3 origin
customOriginSource: {
domainName: `${httpApi.httpApiId}.execute-api.${this.region}.amazonaws.com`,
},
behaviors: [
{
pathPattern: "/api/*", // CloudFront will forward `/api/*` to the backend so make sure all your routes are prepended with `/api/`
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: Duration.seconds(0),
forwardedValues: {
queryString: true,
headers: ["Authorization"], // By default CloudFront will not forward any headers through so if your API needs authentication make sure you forward auth headers across
},
},
],
},
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
];
ハンドリングリダイレクトのためのラムダエッジ
注意:一旦作成したらLambda@Edge削除するには時間がかかる.
あなたのCDKアプリのlibフォルダの中にredirect
で、index.ts
以下の内容でファイルをインクルードしますLambda@Edge):
"use strict";
exports.handler = (event: any, context: any, callback: any) => {
const response = event.Records[0].cf.response;
const request = event.Records[0].cf.request;
/**
* This function updates the HTTP status code in the response to 302, to redirect to another
* path (cache behavior) that has a different origin configured. Note the following:
* 1. The function is triggered in an origin response
* 2. The response status from the origin server is an error status code (4xx or 5xx)
*/
if (response.status == 404) {
const redirect_path = `/`; //redirects back to root so to index.html
response.status = 302;
response.statusDescription = "Found";
/* Drop the body, as it is not required for redirects */
response.body = "";
response.headers["location"] = [{ key: "Location", value: redirect_path }];
}
callback(null, response);
};
今、あなたのCDKにラムダリソースを追加します(後でこの分布の中でラムダを参照するときに、これがクラウドフロントディストリビューションリソースの前にあることを確認してください):
const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
最後にこれを関連付けるLambda@EdgeS 3の起源で
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
lambdaFunctionAssociations: [
{
lambdaFunction: redirectLambda.currentVersion,
eventType: LambdaEdgeEventType.ORIGIN_RESPONSE,
},
],
},
],
},
テストする
次のエンドポイントを訪問してください/
こんにちは世界インデックスを返します.HTMLページ
/api/helloworld
マシンフレンドリーメッセージを返す必要があります
/api/non-existent-endpoint
バックエンドAPI
そしてついに/non-existent-page
我々のインデックスに我々をリダイレクトしなければなりません.我々はWebアプリの中でそれを処理することができますので、HTML
キーテイク
以下は、CDKを使用して作業例を構築するステップバイステップチュートリアルです.
参考のために、ローカルにインストールしたものです.
$ node --version
v14.13.1
$ yarn --version # you can use npm
1.22.5
$ cdk --version
1.67.0 (build 2b4dd71)
$ docker --version # used by CDK to compile typescript lambdas
Docker version 19.03.13, build 4484c46d9d
すべてのソースコードをここで見つけることもできます.EVNZ / ブログCFシングル配布
S 3バケツとAPIゲートウェイバックエンドでホストされるあなたのウェブアプリのための一つのアマゾンCloudfront配布の例
CDKセットアップ
タイプスクリプトCDKプロジェクトを作成し、いくつかの依存関係をインストールしましょう.
$ cdk init app --language typescript
...
$ yarn add \
@aws-cdk/aws-cloudfront \
@aws-cdk/aws-apigatewayv2 \
@aws-cdk/aws-s3 \
@aws-cdk/aws-s3-deployment \
@aws-cdk/aws-lambda \
@aws-cdk/aws-lambda-nodejs \
@aws-cdk/aws-iam
...
$ yarn add --dev --exact [email protected] # for compiling typescript lambdas
ラムダバックエンドを持つAPIゲートウェイ
あなたのCDKアプリのlibフォルダの中に
backend
とダミーのラムダ関数を設定します(index.ts
) これは200を返します:export const handler = async (event: any): Promise<any> => {
return {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ key: "Machine friendly hello world" }),
};
};
必要なインポートを追加lib/{your-stack-name}.ts
ファイルimport * as cdk from "@aws-cdk/core";
import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
import { Runtime } from "@aws-cdk/aws-lambda";
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
ここでは、CDKスタックに次のコードを追加してラムダ関数を作成し、API GateWavv 2と統合できます.const httpApi = new apigatewayv2.HttpApi(this, "MyApiGateway");
const helloWorldLambda = new NodejsFunction(this, "HelloWorldLambda", {
entry: `${__dirname}/backend/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
const lambdaIntegration = new apigatewayv2.LambdaProxyIntegration({
handler: helloWorldLambda,
});
httpApi.addRoutes({
path: "/api/helloworld", // You must include the `/api/` since CloudFront will not truncate it
methods: [apigatewayv2.HttpMethod.GET],
integration: lambdaIntegration,
});
3 . S 3バケットとクラウドフロントディストリビューション
あなたのCDKアプリのlibフォルダの中に
frontend
で、index.html
いくつかのHTMLコンテンツでファイルを<html>
<body>
Hello world
</body>
</html>
以下のCDK依存関係をインポートしますlib/{your-stack-name}.ts
ファイルimport * as cloudfront from "@aws-cdk/aws-cloudfront";
import * as s3 from "@aws-cdk/aws-s3";
import * as iam from "@aws-cdk/aws-iam";
import { Duration } from "@aws-cdk/core";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";
今、プライベートのS 3のバケツを使用して標準的な静的なウェブサイトを作成することができますCloudfrontの配布とすべての間(iams、オアシスなど).const cloudfrontOAI = new cloudfront.OriginAccessIdentity(
this,
"cloudfrontOAI",
{
comment: `Allows CloudFront access to S3 bucket`,
}
);
const websiteBucket = new s3.Bucket(this, "S3BucketForWebsiteContent", {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
cors: [
{
allowedOrigins: ["*"],
allowedMethods: [s3.HttpMethods.GET],
maxAge: 3000,
},
],
});
// uploads index.html to s3 bucket
new s3deploy.BucketDeployment(this, "DeployWebsite", {
sources: [s3deploy.Source.asset(`${__dirname}/frontend`)], // folder containing your html files
destinationBucket: websiteBucket,
});
websiteBucket.addToResourcePolicy(
new iam.PolicyStatement({
sid: "Grant Cloudfront Origin Access Identity access to S3 bucket",
actions: ["s3:GetObject"],
resources: [websiteBucket.bucketArn + "/*"],
principals: [cloudfrontOAI.grantPrincipal],
})
);
const cloudfrontDistribution = new cloudfront.CloudFrontWebDistribution(
this,
"MyDistribution",
{
comment: "CDN for Web App",
defaultRootObject: "index.html",
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
originConfigs: [
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
],
}
);
別のCloudfront起源としてAPIゲートウェイを加えてください
APIゲートウェイを別の起源として追加する
/api/*
CloudFrontディストリビューション(APIゲートウェイの原点がS 3の原点より上にあることを確認してください)/api/*
先読みをする)originConfigs: [
{
// make sure your backend origin is first in the originConfigs list so it takes precedence over the S3 origin
customOriginSource: {
domainName: `${httpApi.httpApiId}.execute-api.${this.region}.amazonaws.com`,
},
behaviors: [
{
pathPattern: "/api/*", // CloudFront will forward `/api/*` to the backend so make sure all your routes are prepended with `/api/`
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: Duration.seconds(0),
forwardedValues: {
queryString: true,
headers: ["Authorization"], // By default CloudFront will not forward any headers through so if your API needs authentication make sure you forward auth headers across
},
},
],
},
{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
},
],
},
];
ハンドリングリダイレクトのためのラムダエッジ
注意:一旦作成したらLambda@Edge削除するには時間がかかる.
あなたのCDKアプリのlibフォルダの中に
redirect
で、index.ts
以下の内容でファイルをインクルードしますLambda@Edge):"use strict";
exports.handler = (event: any, context: any, callback: any) => {
const response = event.Records[0].cf.response;
const request = event.Records[0].cf.request;
/**
* This function updates the HTTP status code in the response to 302, to redirect to another
* path (cache behavior) that has a different origin configured. Note the following:
* 1. The function is triggered in an origin response
* 2. The response status from the origin server is an error status code (4xx or 5xx)
*/
if (response.status == 404) {
const redirect_path = `/`; //redirects back to root so to index.html
response.status = 302;
response.statusDescription = "Found";
/* Drop the body, as it is not required for redirects */
response.body = "";
response.headers["location"] = [{ key: "Location", value: redirect_path }];
}
callback(null, response);
};
今、あなたのCDKにラムダリソースを追加します(後でこの分布の中でラムダを参照するときに、これがクラウドフロントディストリビューションリソースの前にあることを確認してください):const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
最後にこれを関連付けるLambda@EdgeS 3の起源で{
s3OriginSource: {
s3BucketSource: websiteBucket,
originAccessIdentity: cloudfrontOAI,
},
behaviors: [
{
compress: true,
isDefaultBehavior: true,
defaultTtl: Duration.seconds(0),
allowedMethods:
cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
lambdaFunctionAssociations: [
{
lambdaFunction: redirectLambda.currentVersion,
eventType: LambdaEdgeEventType.ORIGIN_RESPONSE,
},
],
},
],
},
テストする
次のエンドポイントを訪問してください
/
こんにちは世界インデックスを返します.HTMLページ/api/helloworld
マシンフレンドリーメッセージを返す必要があります/api/non-existent-endpoint
バックエンドAPIそしてついに
/non-existent-page
我々のインデックスに我々をリダイレクトしなければなりません.我々はWebアプリの中でそれを処理することができますので、HTMLキーテイク
代替案
If Lambda@Edgeお好みに合わない場合は、代わりに以下の選択肢を試してみてください.
以下のコメント欄でのフィードバックと質問歓迎
Reference
この問題について(S 3 WebアプリとAPIゲートウェイのための単一のCloudfront配布), 我々は、より多くの情報をここで見つけました https://dev.to/evnz/single-cloudfront-distribution-for-s3-web-app-and-api-gateway-15c3テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol