Programming/Sabujak Sabujak

AWS Lambda@edge 사용해서 ".html" 지워버리기 (feat. NextJS)

mingule 2022. 4. 30. 13:51

NextJS를 사용해서 배포하면, 뒤에 www.test-url.com/home.html (가칭) 이런 형태로 뒤에 html이 붙는 걸 확인할 수 있다. 

그냥 React.js를 활용할 때와는 달리, NextJS는 SSR을 활용하기 때문에, 이런 현상이 있는 것 같다.

이런 형태의 URL은 도저히 용납할 수 없는(?) 형태였기 때문에, 최우선순위를 두고 찾아봤다. 

어떻게 검색해야 할 지도 약간 가늠이 안가서, 초반엔 좀 고생을 했다. dynamic routes 하면 /post/[id] 형태로 나오는 친구들을 라우팅해주는 이야기만 나오고.. 흑흑.. 하지만 해결했다. 기분니가 좋다. 후후

 

해결한 방법에 대해 간략하게 정리해보겠다. 

아래 해결방법은 Next.js + S3 + Cloudfront로 이미 프로젝트가 배포가 되어있는 것을 전제로 한다. 만약 아직 프로젝트가 배포가 되지 않았다면, https://mingule.tistory.com/70 에서 배포에 관한 내용을 스알짝 보고 오는 것을 추천! (*React 프로젝트 배포이긴 하지만 Next.js 설정도 거의 비슷해요^^.. 하핫,,) 

 

1. AWS Lambda에 함수 등록해주기.

Lambda 페이지에 들어가서, Create Function을 누른다. (아래는 내가 등록한 뻥션! 후후) 그러면 아래와 같은 페이지가 뜬다.

이름을 등록해주고, Runtime을 골라주면 되는데, 기본으로 Node.js 14버전이 등록되어있다. 나는 기본으로 고르고 넘어갔다.

Create Function을 누르면, 이제 약간의 로딩과 함께 다음 화면으로 넘어간다. (여기에서 함수를 등록해주면 된다)

 

넘어간 페이지에서 아래로 스크롤을  살짝 내리면, 이렇게 함수를 등록하는 곳이 보인다.

기본으로 작성되어있는 코드는 살짝쿵 지워버리고, 이제 https://test-url.com/어쩌구 로 왔을 때, https://test-url.com/어쩌구.html 로 와라 라고 설정해주는 코드를 집어넣으면 된다. (코드는 아래에 있다.) 

const config = {
    suffix: '.html',
    appendToDirs: 'index.html',
    removeTrailingSlash: false,
};

const regexSuffixless = /\/[^/.]+$/; // e.g. "/some/page" but not "/", "/some/" or "/some.jpg"
const regexTrailingSlash = /.+\/$/; // e.g. "/some/" or "/some/page/" but not root "/"
// const dynamicRouteRegex = /\/subpath\/\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/; // e.g /urs/some-uuid; // e.g. '/subpath/uuid'
const dynamicRouteRegex = /^(.+)\/\d+\/?$/; // e.g. /post/123

exports.handler = function handler(event, context, callback) {
    const { request } = event.Records[0].cf;
    const { uri } = request;
    const { suffix, appendToDirs, removeTrailingSlash } = config;


    if(uri.match(dynamicRouteRegex)) {
        request.uri = uri.replace(dynamicRouteRegex, '$1/[id].html')
        callback(null, request);
        return;
    }
    
    // Append ".html" to origin request
    if (suffix && uri.match(regexSuffixless)) {
        request.uri = uri + suffix;
        callback(null, request);
        return;
    }
    
    // Append "index.html" to origin request
    if (appendToDirs && uri.match(regexTrailingSlash)) {
        request.uri = uri + appendToDirs;
        callback(null, request);
        return;
    }

    // Redirect (301) non-root requests ending in "/" to URI without trailing slash
    if (removeTrailingSlash && uri.match(/.+\/$/)) {
        const response = {
            // body: '',
            // bodyEncoding: 'text',
            headers: {
                'location': [{
                    key: 'Location',
                    value: uri.slice(0, -1)
                 }]
            },
            status: '301',
            statusDescription: 'Moved Permanently'
        };
        callback(null, response);
        return;
    }

    // If nothing matches, return request unchanged
    callback(null, request);
};

그러면 이제 Header가 아래처럼 바뀐다. 바뀐 내용들을 배포하라는 뜻인데, 버튼을 눌러주면 된다. 후후,, 

 

2. AWS Lambda에 등록한 함수와 Cloudfront 연결해주기!

자 이제 잘 됐으면, Configuration에서 Trigger를 만들어준다. 우측 상단에 Add Trigger를 눌러 등록할 수 있다.

고러면 아래 페이지처럼 Trigger Configuration을 고를 수 있게 나온다. 여기에서 Cloudfront를 골라주면 된다.

🚨 근데 중요한거! region이 Seoul이면 Cloudfront가 안보인다. 무조건 US East(N.Virginia)로 region을 고르고 진행해야한다.

고러면 이제 Cloudfront가 보일거고, 아래에서 Deploy to Lambda@Edge 버튼을 눌러주면 된다.

버튼을 누르면 아래와 같이 Modal이 뜨는데, 여기에서 빨간색으로 표시된 부분을 체크해주면 된다.

첫번째 Distribution 에서는 내가 연결할 Cloudfront Distribution을 고르면 되고, 마지막은 그냥 체킷체킷 해주면 된다.

그냥 Deploy를 누르면 이제 완료우! 된다.

 

근데 여기에서 또 문제가 생길 수 있다. 대략 아래와 같은 에러인데.. 더 길게 오류가 나는 경우도 있다. ^^ (유경험자)

이 부분은 IAM에서 Role 부분을 업데이트시켜주면 해결된다.

얼른 IAM Role로 이동해보자.

 

3. IAM Role 업데이트 시켜주기.

요기로 들어가면, 내가 아까 만들었던 람다에 대한 Role이 생성되어있는 것을 확인할 수 있다.

여기에서 Trust Relationships에 들어가서, edit하기를 누른다음에, 아까 저 빨간 오류 친구가 말했던 edgelambda.amazonaws.com 을 등록해주면 된다. 아래는 복사하실 분들을 위한 코드블락 삽입 (센스 미춌따 😎 뎨둉합니다)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "edgelambda.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

이렇게 되면, 거진 동작을 할텐데 만약에 혹시라도! 내가 role을 만들때 지웠다 새로 만들었다 난리부루스방귀뿡뿡을 꼈다면, 살짝 꼬여있을 수도 있다. (나도 알고싶지않았다. 하하.) 

그럴 때에는, Lambda / Function의 Configuration에 들어가서 Permission Tab의 Execution Role 이름과, 내가 IAM에서 만든 Role의 이름이 같은지 확인해주면 된다. 다르게 되어있다면 온농 바꾸어주자. 

 

4. 완료우!

그러고, 조금 기다리거나 Cloudfront Invalidation을 한번 삭- 해줘서 캐싱삭제를 해주면 이제 잘 돌아가는 것을 확인할 수 있다.

감똥적. 흑흑.

 

생각보다 쉬운 작업이었당. 

다들 이 포스팅을 보면서 고생하지 않고, 설정을 잘 할 수 있기를 바라며.. 포슷힝을 마칩니다.

꺄!!!!!!!!!!!!!!!!!!