강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

재환님의 프로필 이미지
재환

작성한 질문수

한 입 크기로 잘라먹는 실전 프로젝트 - SNS 편

(7.4) 이미지 업로드 구현하기 2

여러 사진 중 일부 사진의 허용 사이즈 초과로 실패한 경우에 대해

작성

·

18

1

안녕하세요 정환님! 항상 강의 감사한 마음으로 잘 듣고 있습니다. 이번 이미지 업로드 구현하기2 강의를 끝까지 듣고 따라하던중 스토리지에 이미지 업로드 병렬로 요청 시 제가 업로드 시도한 이미지 4장 중 1장이 허용 사이즈 초과로 스토리지 업로드 요청이 실패 했었는데요, 당연히 이미지 업로드 실패로

await deletePost(post.id);

가 호출되 post.id를 받기위해 먼저 생성한 포스트가 삭제되어 포스트 자체가 안된것처럼 동작했습니다. 근데 storage에서는 업로드 요청이 실패된 이미지를 제외하고 나머지 3장의 이미지가 저장이 되어있더라고요!

간단하게 4장 병렬 이미지 업로드 요청 > 3장 성공 1장 실패 > 이미지 업로드 일부 실패로 포스트 삭제 > storage에는 성공한 3장의 이미지만 존재, 포스트는 없음

이 상태여서 혼자 찾아봐서 추가해봤는데 맞는지도 궁금하고 맞다면 다른 분들도 비슷한 상황에서 도움이 될까 싶어 올립니다!!

images.ts 파일에 스토리지에서 이미지 삭제하는 비동기 요청 함수

export async function deleteImages(filePath: string[]) {
  const { data, error } = await supabase.storage
    .from(BUCKET_NAME)
    .remove(filePath);

  if (error) throw error;
  return data;
}

post.ts > createPostWithImages 함수 에서 try, catch문 밖에 업로드전 생성한 filePath 저장할 배열 값을 갖는 변수 선언

  const uploadedFilePaths: string[] = [];
const imageUrls = await Promise.all(
      images.map((image) => {
        const fileExtension = image.name.split(".").pop() || "webp";
        const fileName = `${Date.now()}-${crypto.randomUUID()}.${fileExtension}`;
        const filePath = `${userId}/${post.id}/${fileName}`;

        uploadedFilePaths.push(filePath);
        return uploadImage({
          file: image,
          filePath,
        });
      }),
    );

uploadImage 리턴 전에 생성한 filePath값 저장

catch문에서

if (uploadedFilePaths.length > 0) {
      await deleteImages(uploadedFilePaths);
    }

조건문 추가

최종 결과
병렬 요청중 일부의 요청이 파일의 크기 초과 등으로 실패하면
throw error >

await deletePost(post.id);
    if (uploadedFilePaths.length > 0) {
      await deleteImages(uploadedFilePaths);
    }
    throw error;


포스트 삭제, 스토리지 이미지 삭제

글을 잘 못써서 가독성이 떨어지는 부분은 양해부탁드립니다..

답변 2

0

재환님의 프로필 이미지
재환
질문자

반영 코드 도움되시는분 있으실까 첨부합니다

export async function createPostWithImages({
  content,
  images,
  userId,
}: {
  content: string;
  images: File[];
  userId: string;
}) {
  // 1. 새로운 포스트 생성
  const post = await createPost(content);

  if (images.length === 0) return post;

  const uploadedFilePaths: string[] = [];

  try {
    // 2. 이미지 업로드

    const imageUrls = await Promise.all(
      images.map((image) => {
        const fileExtension = image.name.split(".").pop() || "webp";
        const fileName = `${Date.now()}-${crypto.randomUUID()}.${fileExtension}`;
        const filePath = `${userId}/${post.id}/${fileName}`;

        uploadedFilePaths.push(filePath);
        return uploadImage({
          file: image,
          filePath,
        });
      }),
    );

    // 3. 포스트 테이블 업데이트
    const updatedPost = await updatePost({
      id: post.id,
      image_urls: imageUrls,
    });
    return updatedPost;
  } catch (error) {
    await Promise.all([
      deletePost(post.id),
      uploadedFilePaths.length > 0
        ? deleteImages(uploadedFilePaths)
        : Promise.resolve(),
    ]);
    throw error;
  }
}

0

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

안녕하세요 재환님 이정환입니다.

앗! 그렇네요 🥲 이런 이슈가 있을 수 있겠군요

해당 이슈를 해결하려면 재환님이 말씀해주신 대로 catch 문에서 업로드 된 이미지 전체를 삭제하는 로직을 추가해주시면 됩니다!

한가지 코멘트를 남기자면 await deletePost와 await deleteImages는 Promise.all을 통해 묶어 병렬처리하면 더 깔끔할 것 같아요!

재환님의 프로필 이미지
재환
질문자

더 깔끔한 방법 알려주셔서 감사합니다!!

재환님의 프로필 이미지
재환

작성한 질문수

질문하기