최적화된 이미지 서버를 사용하여 이미지 데이터 관리하기(with CloudFlare)

Mincho·2023년 6월 3일
0

[프로젝트]

목록 보기
5/5

🔴 이미지를 어떻게 관리해야 할까??

프로젝트 진행과정 당시 이미지를 어떻게 처리해주어야 할지 고민을 하게 되었다. 이미지를 백엔드 서버 DB에 바로 저장해 둘 수 있지만 이미지가 많은 경우 데이터 베이스 성능이 저하될 수 있으며, 디비를 계속해서 호출해야 하기 때문에 비효율적 일 수 있다고 판단했다. 그렇기 때문에 따로 이미지 서버를 사용하는 것이 좋다고 생각하여 CloudFlare를 사용하기로 했다.



🟠 CloudFlare

 CloudFlare는 전문 CDN(Contents Delivery Network)업체이다. 비교적 저렴한 가격에 이미지 비용을 지불해 사용할 수 있고, 이미지에 대한 최적화 기능과 보안 기능을 제공한다.
CloudFlare 공식 페이지



🟡 어떠한 방식으로 관리하는 것일까?

업로드하는 과정
1. 클라이언트측에서 백엔드 서버로 이미지를 담을 url을 요청한다.
2. 백엔드 서버에서는 클라이언트의 요청을 받고 CloudFlare 이미지 서버로 이미지 담을 url을 요청한다.
3. CloudFlare이미지 서버에서 url정보를 백엔드 서버에 응답한다.
4. 백엔드 서버에서 url정보를 클라이언트에 응답한다.
5. 클라어인트는 응답받는 url로 직접 이미지를 업로드한다.
6. 업로드하게 되면 업로드 된 url을 응답받게 된다.
7. 이 응답받은 url을 백엔드 서버에 저장시킨다.

 클라이언트측에서 업로드하고 싶은 이미지를 CloudFlare서버로 업로드하기 위해서는 CludFlare로 바로 업로드하는 것이 아니라 CloudFlare에서 제공하는 url로 이미지 데이터를 보내야 한다.
그런데 이것을 클라이언트 측에서 바로 요청하면 문제가 생길 수 있다.

 클라이언트가 직접적으로 CloudFlare 이미지서 API에 접근하기 위해서 사용되는 key값들이 노출될 수 있기 때문이다. 그렇기에 백엔드 서버를 통해서 과정을 이루어야한다.



🟢 프론트/백 해결과정

프론트엔드

/**사진을 업로드 할 url 가져오는 함수. */
export const getUploadUrl = async (img) => {
  let resData = "";
  await axios
    .post(`${BASE_URL}media/photos/get-url/`, img.file, {
      withCredentials: true,
    })
    .then((data) => {
      resData = uploadImg(data, img);
      return resData;
    })
    .catch(() => {
      resData = false;
      return resData;
    });

  return resData;
};

/**받아온 url에 이미지 넣어주기*/
export const uploadImg = async (data, img) => {
  let resData = "";
  const form = new FormData();
  form.append("file", img.file[0]);
  await axios
    .post(data.data.uploadURL, form, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
      withCredentials: false,
    })
    .then((res) => {
      resData = res.data.result;
      return res.data.result;
    });

  return resData;
};

 프론트엔드에서 getUploadUrl함수를 통해 url을 받아오는데 성공하면 upLoadImg함수를 실행시켰다.

 여기서 중요한 점은 이미지서버에 이미지를 첨부할때는 FormData형식으로 보내야한다는 점이다. 이 것은 뒤에서 제대로 알아보도록 하자!

백엔드

//CloudFlare이미지 서버에 url요청받아서 응답
class GetUploadURL(APIView):
    def post(self, request):
        url= f"https://api.cloudflare.com/client/v4/accounts/{settings.CF_ID}/images/v2/direct_upload"
        one_time_url = requests.post(url, headers={
            "Authorization":f"Bearer {settings.CF_TOKEN}"
        })
        one_time_url = one_time_url.json()
        result=one_time_url.get('result')
        return Response({"id":result.get("id"), "uploadURL": result.get('uploadURL')})

 위의 코드는 백엔드 Djnago서버의 코드로 클라이언트에서 url을 요청 받으면 CloudFlare에서 url을 요청하여 응답받아 전달해준다.



🔵 FormData

  서버와의 통신과정에서 HTTP통신 규약을 지키게 되는데, Request요청에 Header로 어떤 데이터를 전송할 것인지 Content-Type을 추가하여 전송한다. 보통 Json형식으로 많이 사용한다.

  그런데 이미지 데이터는 이미지 파일 자체를 전송하는게 아니라 파일을 문자로 변환하여 body에 담아보내는 것이다. 여기서 아까 프론트엔드 코드를 다시 살펴보자

/**받아온 url에 이미지 넣어주기*/
export const uploadImg = async (data, img) => {
  let resData = "";
  const form = new FormData();
  form.append("file", img.file[0]);
  await axios
    .post(data.data.uploadURL, form, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
      withCredentials: false,
    })
    .then((res) => {
      resData = res.data.result;
      return res.data.result;
    });

  return resData;
};

 다음과 같이 이미지 파일을 보낼때 formData에 이미지를 넣고 header에는 Content-Type으로 multipart/form-data형식으로 보내는 것을 알 수 있다. 이렇게 생성자를 이용해 formData를 만들어 파일을 보내는 이유는 무엇일까??

1.데이터의 안정성과 보안성 향상
2.파일 업로드를 위한 별도의 라이브러리 설치 필요없음
3.여러개의 파일과 함께 업로드 가능

 이러한 장점을 가지고 있기 때문에 보통 이미지 서버로 활용되는 CDN업체는 FormData로 정보를 받고 있다.



참고자료
https://www.cloudflare.com/ko-kr/products/cloudflare-images/
https://stack94.tistory.com/entry/JavaScript-FromData-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B3%A0-%EC%84%9C%EB%B2%84%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%A0%84%EC%86%A1%ED%95%B4%EB%B3%B4%EC%9E%90

👍올바른 피드백은 언제든지 환영입니다~!

profile
사진찍는 개발자.

0개의 댓글