S3 웹 앱 및 API 게이트웨이를 위한 단일 CloudFront 배포
33415 단어 cloudfronts3apigatewayaws
내가 이루고 싶은 결과:
website.com
내 웹 응용 프로그램 불러오기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 버전을 동시에 사용해야 합니까?E, g. 왜 나는 website.com
과api.website.com
만 사용할 수 없습니까?
요컨대 자역은 관리하기 어려울 수도 있고, 일부 조직에서는 새로운 자역을 요청하기도 어려울 수도 있다.
하위 도메인 관리가 어려울 수 있는 하나의 예는 서로 다른 환경이다.아래 하위 영역dev.website.com
을 가진 개발 환경이 있다고 가정하십시오.APIapi.dev.website.com
입니까, 아니면 dev.api.website.com
입니까?개별 SSL 인증서를 생성하시겠습니까?당신의 CORS 규칙은요?CSP는요?코드 라이브러리에서 이 점을 어떻게 관리하시겠습니까?
...나는 영원히 계속할 수 있다.
따라서 일부는 /api/
만 사용하고 여기까지를 고려할 수도 있다.이 게시물은 그 사람들을 위해 쓴 것이다.
총결산
기본적으로 우리는 경로 모델을 바탕으로 여러 출처에서 CloudFront 서비스를 제공할 것이다.이 경우 Cloudfront는 모든 요청/api/*
을 API 게이트웨이로 전송하고 다른 모든 요청을 S3로 전송합니다.이 하나만으로도 결과 1, 3, 4를 실현할 수 있다.
그러나 만약 누군가가 접근을 시도한다면/non-existent-page
S3에서 "NoSuchKey"오류를 얻을 것입니다. 이것은 우리의 인성화된 404 오류가 아닙니다.
CloudFront 사용자 정의 오류 구성을 사용하여 모든 404 오류를 덮어쓰고 색인을 만드는 것이 어떻습니까?html 아니면 전용 404페이지?불행하게도 CloudFront는 현재 모든 원본의 사용자 정의 오류 설정을 설정할 능력이 없기 때문에 우리의 경우 백엔드 API 오류 응답을 덮어씁니다. (기본적으로 우리가 해결하고자 하는 문제의 핵심입니다.)
따라서 사용자 정의 오류 설정은 불가능합니다. 우리는...
그래, 네가 알아맞혔으니,Lambda@edge.
저희가 사용할 수 있어요.Lambda@EdgeS3 원점으로 가는 /non-existent-page
루트의 경우 404 응답을 인덱스로 다시 지정합니다.html 또는 전용 404페이지.
건축학
아주 직접적이야. 우리 하나만 필요해.Lambda@Edge우리의 S3 기원과 분포 사이.
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
또한 여기에서 모든 소스 코드와 배포 작업의 예에 대한 설명을 찾을 수 있습니다.
회사 명
/
블로그 예시
S3 bucket 및 API 게이트웨이 백엔드에서 관리되는 웹 응용 프로그램의 단일 Amazon CloudFront 배포 예
CDK 설정
typescript 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
Lambda 백엔드가 있는 API 게이트웨이
CDK 응용 프로그램의lib 폴더에 backend
라는 폴더를 만들고 200으로 되돌아오는 위조 lambda 함수(index.ts
를 놓습니다.
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 스택에 추가하여 lambda 함수를 만들고 API GatewayV2와 통합할 수 있습니다.
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.S3 Bucket 및 CloudFront 배포
CDK 응용 프로그램의 lib 폴더에 frontend
라는 폴더를 만들고 index.html
파일을 만듭니다. html 내용을 포함합니다.
<html>
<body>
Hello world
</body>
</html>
lib/{your-stack-name}.ts
파일에서 다음 CDK 종속성을 가져옵니다.
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";
이제 개인 S3 bucket, CloudFront 릴리스와 중간의 모든 것(IAMs, OAIs 등)을 사용하여 표준 정적 사이트를 만듭니다.
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/*
의 경로 일치 우선순위를 위해 API 게이트웨이가 S3 소스 위에 있는지 확인합니다).
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 테두리
참고: 생성된 경우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에 Lambda 리소스를 추가합니다(CloudFront에서 리소스를 배포하기 전에 나중에 배포에서 이 Lambda를 참조하므로).
const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
마지막으로 연락드릴게요.Lambda@Edge우리의 S3 출처:
{
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,
},
],
},
],
},
테스트 해봐.
cloudfront URL을 사용하여 다음 노드에 액세스하십시오./
Hello World 인덱스로 돌아가야 합니다.html 페이지
/api/helloworld
우리에게 기계의 우호적인 소식을 돌려주어야 한다
/api/non-existent-endpoint
백엔드 API에서 처리해야 함
마지막으로 /non-existent-page
우리를 색인으로 다시 지정해야 합니다.html, 이렇게 하면 우리는 우리의 웹 응용 프로그램에서 그것을 처리할 수 있다
주요 배달
기본적으로 우리는 경로 모델을 바탕으로 여러 출처에서 CloudFront 서비스를 제공할 것이다.이 경우 Cloudfront는 모든 요청
/api/*
을 API 게이트웨이로 전송하고 다른 모든 요청을 S3로 전송합니다.이 하나만으로도 결과 1, 3, 4를 실현할 수 있다.그러나 만약 누군가가 접근을 시도한다면
/non-existent-page
S3에서 "NoSuchKey"오류를 얻을 것입니다. 이것은 우리의 인성화된 404 오류가 아닙니다.CloudFront 사용자 정의 오류 구성을 사용하여 모든 404 오류를 덮어쓰고 색인을 만드는 것이 어떻습니까?html 아니면 전용 404페이지?불행하게도 CloudFront는 현재 모든 원본의 사용자 정의 오류 설정을 설정할 능력이 없기 때문에 우리의 경우 백엔드 API 오류 응답을 덮어씁니다. (기본적으로 우리가 해결하고자 하는 문제의 핵심입니다.)
따라서 사용자 정의 오류 설정은 불가능합니다. 우리는...
그래, 네가 알아맞혔으니,Lambda@edge.
저희가 사용할 수 있어요.Lambda@EdgeS3 원점으로 가는
/non-existent-page
루트의 경우 404 응답을 인덱스로 다시 지정합니다.html 또는 전용 404페이지.건축학
아주 직접적이야. 우리 하나만 필요해.Lambda@Edge우리의 S3 기원과 분포 사이.
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
또한 여기에서 모든 소스 코드와 배포 작업의 예에 대한 설명을 찾을 수 있습니다.
회사 명
/
블로그 예시
S3 bucket 및 API 게이트웨이 백엔드에서 관리되는 웹 응용 프로그램의 단일 Amazon CloudFront 배포 예
CDK 설정
typescript 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
Lambda 백엔드가 있는 API 게이트웨이
CDK 응용 프로그램의lib 폴더에 backend
라는 폴더를 만들고 200으로 되돌아오는 위조 lambda 함수(index.ts
를 놓습니다.
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 스택에 추가하여 lambda 함수를 만들고 API GatewayV2와 통합할 수 있습니다.
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.S3 Bucket 및 CloudFront 배포
CDK 응용 프로그램의 lib 폴더에 frontend
라는 폴더를 만들고 index.html
파일을 만듭니다. html 내용을 포함합니다.
<html>
<body>
Hello world
</body>
</html>
lib/{your-stack-name}.ts
파일에서 다음 CDK 종속성을 가져옵니다.
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";
이제 개인 S3 bucket, CloudFront 릴리스와 중간의 모든 것(IAMs, OAIs 등)을 사용하여 표준 정적 사이트를 만듭니다.
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/*
의 경로 일치 우선순위를 위해 API 게이트웨이가 S3 소스 위에 있는지 확인합니다).
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 테두리
참고: 생성된 경우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에 Lambda 리소스를 추가합니다(CloudFront에서 리소스를 배포하기 전에 나중에 배포에서 이 Lambda를 참조하므로).
const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
마지막으로 연락드릴게요.Lambda@Edge우리의 S3 출처:
{
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,
},
],
},
],
},
테스트 해봐.
cloudfront URL을 사용하여 다음 노드에 액세스하십시오./
Hello World 인덱스로 돌아가야 합니다.html 페이지
/api/helloworld
우리에게 기계의 우호적인 소식을 돌려주어야 한다
/api/non-existent-endpoint
백엔드 API에서 처리해야 함
마지막으로 /non-existent-page
우리를 색인으로 다시 지정해야 합니다.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
또한 여기에서 모든 소스 코드와 배포 작업의 예에 대한 설명을 찾을 수 있습니다.회사 명 / 블로그 예시
S3 bucket 및 API 게이트웨이 백엔드에서 관리되는 웹 응용 프로그램의 단일 Amazon CloudFront 배포 예
CDK 설정
typescript 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
Lambda 백엔드가 있는 API 게이트웨이
CDK 응용 프로그램의lib 폴더에
backend
라는 폴더를 만들고 200으로 되돌아오는 위조 lambda 함수(index.ts
를 놓습니다.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 스택에 추가하여 lambda 함수를 만들고 API GatewayV2와 통합할 수 있습니다.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.S3 Bucket 및 CloudFront 배포
CDK 응용 프로그램의 lib 폴더에
frontend
라는 폴더를 만들고 index.html
파일을 만듭니다. html 내용을 포함합니다.<html>
<body>
Hello world
</body>
</html>
lib/{your-stack-name}.ts
파일에서 다음 CDK 종속성을 가져옵니다.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";
이제 개인 S3 bucket, CloudFront 릴리스와 중간의 모든 것(IAMs, OAIs 등)을 사용하여 표준 정적 사이트를 만듭니다.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/*
의 경로 일치 우선순위를 위해 API 게이트웨이가 S3 소스 위에 있는지 확인합니다).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 테두리
참고: 생성된 경우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에 Lambda 리소스를 추가합니다(CloudFront에서 리소스를 배포하기 전에 나중에 배포에서 이 Lambda를 참조하므로).const redirectLambda = new NodejsFunction(this, "redirectLambda", {
entry: `${__dirname}/redirect/index.ts`,
handler: "handler",
runtime: Runtime.NODEJS_12_X,
});
마지막으로 연락드릴게요.Lambda@Edge우리의 S3 출처:{
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,
},
],
},
],
},
테스트 해봐.
cloudfront URL을 사용하여 다음 노드에 액세스하십시오.
/
Hello World 인덱스로 돌아가야 합니다.html 페이지/api/helloworld
우리에게 기계의 우호적인 소식을 돌려주어야 한다/api/non-existent-endpoint
백엔드 API에서 처리해야 함마지막으로
/non-existent-page
우리를 색인으로 다시 지정해야 합니다.html, 이렇게 하면 우리는 우리의 웹 응용 프로그램에서 그것을 처리할 수 있다주요 배달
선택
하면, 만약, 만약...Lambda@Edge입맛에 맞지 않으므로 다음 대안을 모색해야 할 수도 있습니다.
도움이 됐으면 좋겠어요!
다음 섹션에서 피드백과 질문을 환영합니다:)
Reference
이 문제에 관하여(S3 웹 앱 및 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.)