[개인 프로젝트] CardLog 제작기(5) - AWS S3 이미지 버킷 서버 구축 및 기능 제작 완료

건둔덕 ·2023년 4월 1일
4

CardLog 제작기

목록 보기
5/7
post-thumbnail

이전의 포스팅에선 로그인과 회원가입 부분까지 구현을 했었는데, 처음 해보는 부분이기도 했고 백엔드까지 직접 처리를 해줘야 하다보니 고생을 좀 많이 했었던 것 같다.

하지만 그 부분을 해결하고 나서는 기획했던 대로 쭉쭉 컴포넌트들과 기능을 만들었다.

100% 완성은 아니고, 90%는 만든 것 같다.

AWS S3

우선 게시글 썸네일과 프로필 사진 업데이트 부분을 구현하기 위해선 이미지 서버가 필요했다. 내가 직접 백엔드 부분을 구현해야 하다보니 참 골치가 아파졌다..

이미지 서버는 이미 기획 단계에서 AWS의 S3를 사용하려고 했었다.

1. 버킷 생성

일단은 AWS 안의 S3 페이지로 가서 버킷 만들기를 통해 만들어 줄 수 있었다. 이 부분은 크게 어렵지 않다. 검색만 해도 너무 많은 자료가 있어서 버킷은 그 곳들을 참고하길 바란다!



2. JSON 버킷 정책 설정

{
    "Version": "2012-10-17",
    "Id": "Policy1680030209370",
    "Statement": [
        {
            "Sid": "Stmt1680030202034",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::cardlog-bucket/*"
        }
    ]
}

내가 사용한 JSON 버킷 정책은 위 처럼 만들어서 넣었다. 이 부분은 처음에 어떻게 제작해야 하는지 몰라서 곤란했었는데, 폭풍 검색을 통해 django 프로젝트 진행 시 s3를 기초 세팅할 때 도움이 많이되는 영상을 찾았다.

Django를 사용하면서 AWS S3 초기세팅이 막막한 분들이 참고하면 굉장히 유용할 것 같다.



3. settings.py 내에 AWS 기초 세팅

# AWS S3 Setting

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

AWS_REGION = env('AWS_REGION')
AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = env('AWS_STORAGE_BUCKET_NAME')
AWS_QUERYSTRING_AUTH = False

IMAGE_URL = "https://%s.s3.%s.amazonaws.com/" % (AWS_STORAGE_BUCKET_NAME, AWS_REGION)

위의 값들 처럼 settings.py 파일 내에 세팅해 줬다. 나는 env 파일을 따로 만들어서 그 안에 값들을 중요 값들을 넣어두고 관리하고 있어서 위와 같은 방식으로 값들을 가져와줬다.



4. S3 파일 업로드

pip install boto3
pip install django-storages

위의 패키지를 설치해주고 settings.py 내에 INSTALLED_APPS 안에 추가해준다.

나는 일단 유저의 프로필 이미지를 바꿔주는 기능을 제작했다.

- 프론트엔드에서 이미지 파일 서버로 전송

    const file = (e.target.files as FileList)[0];

    if (file) {
      const formData = new FormData();
      formData.append("files", file);
      formData.append("id", myInfo.id + "");

      api
        .post(`${API_Path.PROFILE_IMAGE}?host_id=profile`, formData, {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        })
        .then((res) => {
          dispatch(setMyInfo({ ...myInfo, profile_img: res.data.profile_img }));
        })
        .catch((error) => console.log(error));
    }

위의 코드를 보면 이미지는 파일 자체를 새로 생성한 FormData 인스턴스에 담아서 데이터를 서버로 전송한다.

위의 path 부분의 host_id 부분은 S3에 이미지를 업로드할 때 넣어줄 폴더 명이다. S3내에 그 이름의 폴더가 없다면 자동 생성되니 없다고해서 문제가 되진 않는다.



- 백엔드에서 받은 파일을 S3에 업로드 및 DB 업데이트

class ProfileImageUpload(View):
    def post(self, request):
        try:
            files = request.FILES.getlist('files')
            host_id = request.GET.get('host_id')
            s3r = boto3.resource('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
            key = "%s"%(host_id)

            for file in files:
                file._set_name(str(uuid.uuid4()))
                s3r.Bucket(AWS_STORAGE_BUCKET_NAME).put_object(Key=key+'/%s'%(file), Body=file, ContentType='image/jpeg')

                user = User.objects.get(pk=request.POST['id'])

                user.profile_img = ("%s/%s"%(host_id, file))
                user.save()

            return JsonResponse({"message": "success", "profile_img": str(user.profile_img)}, status=200)

        except Exception as e:
            return JsonResponse({"error": e})

위의 코드에서는 파일들을 getlist로 받고 있는데, 나는 여러개의 이미지를 받을 수도 있는 상황이 있을 것 같아 일단 getlist 받고 있는 거고 한 개의 파일만 받는다면, get만 사용해도 된다.

아무튼! 받은 파일을 프론트에서 같이 넘겨준 파라미터에있는 host_id와 함께 S3에 업로드하고 User 모델의 profile_img의 값은 host_id와 파일 이름만 넣어서 저장해준다!


저 부분이 실행되면 실제 DB안에는 값이 이렇게 들어오게 된다.


S3 에는 위의 이미지처럼 profile 폴더 안에 이미지가 생성된다.



- 프론트엔드에서 S3에 업로드된 이미지 사용

{myInfo.profile_img ? (
          <img
            src={`https://cardlogbucket.s3.amazonaws.com/${myInfo.profile_img}`}
            alt=""
          />
        ) : (
          <FaUserCircle />
        )}

이제 내 정보안에 저장되어 있는 이미지를 가져와서 사용할 때는 위와 같은 방식을 사용하게되면 프로필 이미지가 있을 때는 이미지가 아주 잘 나오고! 없을 때는 아이콘으로 대체된다!



아주 잘 작동한다!

profile
건데브

0개의 댓글