이전에 한번 구성하였던 기능이나, s3 버켓이 바뀌게 되면서 새로 구성할 필요성이 생기게 되었습니다. 다시 새로 구성하려고 하니 하나도 기억이 나지 않아 정리하여 남겨둡니다.
보다 자세한 절차는 참조 링크에 자세히 남겨져 있으니 참고하시면 됩니다.
CloudFront를 연결하기 위한 버킷 생성합니다. 버킷 내의 디렉토리 구조는 /dev
,/pro
로 만들어 개발과 운영 환경을 구분해 테스트를 자유롭게 하고자 합니다.
Cache and origin request settings
에 Use legacy cache settings 으로 설정Compress Objects Automatically
Yes로 설정.현재는 cloudfront에서 임시로 발급 받은 URL을 사용하지만 추후에 SSL인증서 등록 후 개인적으로 원하는 URL을 등록할수 있습니다.
생성을 완료하면 CloudFront Distributions
메뉴에서 새로 생성된 것을 확인할 수 있습니다.
pro
와 dev
디렉토리에 대해 앞에서 진행한 설정과 동일하게 맞춰서 behavior들을 추가합니다.
생성 후 패턴 우선순위도 변경
/pro
, /dev
, /
경로 각각에 sunglasses_smile.png를 올려둔다.CloudFront Distributions
에서 확인 되는 Domain Name 뒤에 sunglasses_smile.png을 호출하여 적용 되는지 확인람다 함수가 여러 서비스에 접근 가능하도록 IAM 역할을 조합하여 정책을 생성합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"lambda:GetFunction",
"lambda:EnableReplication",
"cloudfront:UpdateDistribution",
"s3:GetObject",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": "*"
}
]
}
Service
부분에 "edgelambda.amazonaws.com" 추가 후 업데이트서울
리전을 지원하므로 서울 리전으로 진행합니다.Sharp
패키지를 설치ec2-user:~/environment $ cd ResizeImage
ec2-user:~/environment/ResizeImage $ npm init -y
...
ec2-user:~/environment/ResizeImage $ npm install sharp
ec2-user:~/environment/ResizeImage $ npm install aws-sdk
'use strict';
const querystring = require('querystring'); // Don't install.
const AWS = require('aws-sdk'); // Don't install.
// http://sharp.pixelplumbing.com/en/stable/api-resize/
const Sharp = require('sharp');
const S3 = new AWS.S3({
signatureVersion: 'v4',
region: 'ap-northeast-2' // 버킷을 생성한 리전 입력
});
const BUCKET = '[mybucket]' // Input your bucket
// Image types that can be handled by Sharp
const supportImageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'tiff'];
exports.handler = async(event, context, callback) => {
const { request, response } = event.Records[0].cf;
// Parameters are w, h, f, q and indicate width, height, format and quality.
const { uri } = request;
const ObjectKey = decodeURIComponent(uri).substring(1);
const params = querystring.parse(request.querystring);
const { w, h, q, f } = params
/**
* ex) https://dilgv5hokpawv.cloudfront.net/dev/thumbnail.png?w=200&h=150&f=webp&q=90
* - ObjectKey: 'dev/thumbnail.png'
* - w: '200'
* - h: '150'
* - f: 'webp'
* - q: '90'
*/
// 크기 조절이 없는 경우 원본 반환.
if (!(w || h)) {
return callback(null, response);
}
const extension = uri.match(/\/?(.*)\.(.*)/)[2].toLowerCase();
const width = parseInt(w, 10) || null;
const height = parseInt(h, 10) || null;
const quality = parseInt(q, 10) || 100; // Sharp는 이미지 포맷에 따라서 품질(quality)의 기본값이 다릅니다.
let format = (f || extension).toLowerCase();
let s3Object;
let resizedImage;
// 포맷 변환이 없는 GIF 포맷 요청은 원본 반환.
if (extension === 'gif' && !f) {
return callback(null, response);
}
// Init format.
format = format === 'jpg' ? 'jpeg' : format;
if (!supportImageTypes.some(type => type === extension )) {
responseHandler(
403,
'Forbidden',
'Unsupported image type', [{
key: 'Content-Type',
value: 'text/plain'
}],
);
return callback(null, response);
}
// Verify For AWS CloudWatch.
console.log(`parmas: ${JSON.stringify(params)}`); // Cannot convert object to primitive value.\
console.log('S3 Object key:', ObjectKey)
try {
s3Object = await S3.getObject({
Bucket: BUCKET,
Key: ObjectKey
}).promise();
console.log('S3 Object:', s3Object);
}
catch (error) {
responseHandler(
404,
'Not Found',
'The image does not exist.', [{ key: 'Content-Type', value: 'text/plain' }],
);
return callback(null, response);
}
try {
resizedImage = await Sharp(s3Object.Body)
.resize(width, height)
.withMetadata()
.toFormat(format, {
quality
})
.toBuffer();
}
catch (error) {
responseHandler(
500,
'Internal Server Error',
'Fail to resize image.', [{
key: 'Content-Type',
value: 'text/plain'
}],
);
return callback(null, response);
}
// 응답 이미지 용량이 1MB 이상일 경우 원본 반환.
if (Buffer.byteLength(resizedImage, 'base64') >= 1048576) {
return callback(null, response);
}
responseHandler(
200,
'OK',
resizedImage.toString('base64'), [{
key: 'Content-Type',
value: `image/${format}`
}],
'base64'
);
/**
* @summary response 객체 수정을 위한 wrapping 함수
*/
function responseHandler(status, statusDescription, body, contentHeader, bodyEncoding) {
response.status = status;
response.statusDescription = statusDescription;
response.body = body;
response.headers['content-type'] = contentHeader;
if (bodyEncoding) {
response.bodyEncoding = bodyEncoding;
}
}
console.log('Success resizing image');
return callback(null, response);
};
cloud9에서 람다 업로드 후 람다 콘솔로 재접속하여, 업로드한 람다 함수 정보로 이동합니다.
우측상단 > 작업 > Lambda@edge 배포 클릭
캐시 동작은 개발환경의 테스트를 위해 dev/*
선택
CloudFront 이벤트는 오리진 응답(Origin response)
을 선택
origin 에서 리소스 존재 여부를 판단 후 존재하면, 함수를 실행시켜야 하기 때문
배포 클릭
이미지 변환 확인
pro/*
, *
경로들도 CloudFront 트리거에서 동일하게 추가
각 경로에서 이미지 변환이 잘 되는지 확인
react native 안에서는 resizeing 이미지 어떻게 호출하시나여? 커맨드로 사용하시나요? 보안적인 측면을 고려했을 때 RN에서 어떻게 사용하면 좋을지 궁금합니다