행복을 담는 블로그

[트러블 슈팅🔥] image url은 있는데 사진이 안 뜸 with supabase storage 본문

TIL

[트러블 슈팅🔥] image url은 있는데 사진이 안 뜸 with supabase storage

hyun0zin 2024. 4. 4. 16:46

트러블 슈팅🔥

문제 1) image url은 잘 들어오는데 사진이 안 뜨는 상황

댓글을 작성하는 페이지에서 다른 값들은 다 comment에 잘 담겨서 들어와서 해당 data를 렌더링 해주는데 문제가 없었는데, 이미지만 잘 안 불러와지는 문제가 생겼었다.

console.log를 계속 찍어서 확인도 해보고, 이미지 url도 복사해서 넣어보고 하니 사진이 잘 뜨는데

src={comment.image[0]} 에서만 사진을 불러오지 못하고 있었다.

<img
        src={comment.image[0]}
        alt="클래스 대표 사진"
        width={300}
        height={200}
        className="w-full h-full p-4"
        style={{ objectFit: 'contain' }}
/>

 

문제 원인 파악)

다른 mainpage에서는 image로 url을 잘 받아오고 있고, 메인 화면에서도 잘 뜨고 있음… 뭐지..

둘의 차이점이 무엇일까 비교하던 중 문제점 파악!!

내가 위에서 받아오고 있던 후기 작성하기에서는 image 자체를 ‘ ’ 바로 이 따옴표 안에서 string 으로 받아오고 있었기 때문…!!!

우리는 image 파일 여러 개를 넣기 위해 type을 array로 선택하였고, 그 중에서도 첫 번째 사진을 대표 사진으로 생각하고 src={comment.image[0]} 이렇게 사진을 넣으려고 했다.

하지만 현재 image 데이터 자체가 string 이기 때문에, 배열의 기능을 상실하고 index 0의 경우 그냥 { 만 들어오고 있었던 셈…!

왜 이부분만 따로 콘솔 찍어볼 생각을 못했을까…

image: '{https://d1x9f5mf11b8gz.cloudfront.net/class/20220308/ec9fa67b-0040-413d-ae8b-258d46df07c4.jpg}'

근데 여기서 image data가 string으로 들어오고 있던 이유는 바로 db join을 통해서 데이터를 받고 있었는데, image를 array가 아닌 text로 받아오고 있었기 때문…!!!

CREATE OR REPLACE FUNCTION fetch_class_info_on_comment(p_user_id uuid) 
RETURNS TABLE (
  class_id uuid,
  comment_id uuid,
  title text,
  image text,
  content text,
  create_at timestamp
) AS $$
SELECT
  c.class_id,
  m.comment_id,
  c.title,
  c.image,
  m.content,
  m.create_at
FROM
  comments m
JOIN
  class c ON m.class_id = c.class_id
WHERE
  m.user_id = p_user_id;
$$ LANGUAGE sql STABLE;

 

문제 해결)

여기서 image text 이 부분을 image text[] 이렇게 image가 array로 들어오도록 해주면 바로 값이 배열에 담긴채 들어오고 있는 걸 확인 할 수 있었다!!

하지만 기존의 함수에서 바로 수정을 하니 error를 뱉어서 새로운 New query를 생성해서 함수를 생성해주었다.

새로운 query 생성해서 하니 잘 작동하였고, 값도 배열로 아주 잘 받아져오는걸 확인 할 수 있었다.

image가 배열 형태로 아주 잘 들어오는걸 확인 할 수 있었다!!

image : ['https://d1x9f5mf11b8gz.cloudfront.net/class/20220308/ec9fa67b-0040-413d-ae8b-258d46df07c4.jpg']

🔥 typescript를 통해 type error를 많이 잡을 수 있었지만, SQL query에서 image type을 text로 작성해주는 것까지 잡아주지는 못 했다..!!

결국은 처음 설정한 type을 잘 지켜주는 것이 매우 중요하다. 정신차리고 코딩하자~~

 

 

문제 2) supabase storage에 업로드한 이미지 url이 404 not found ?!?!

supabase storage에서 이미지 파일을 업로드한 다음 table image data에 추가도 되었고, 콘솔에도 image url이 잘만 뜨는데 왜 404가 뜨는지… 봐도봐도 친해지지 못하는 404 not found

image : ["https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/uploads/b06db7ba-911e-4f4f-993e-147d47118307_143777_149131_434.jpg", …]

문제 원인 파악)

원인 파악을 위해 우선 image url이 실제 storage에 저장된 url과 같은지 확인해보아야 한다.

일단 지난번 팀 프로젝트에서 supabase를 한 번 사용해 본 적이 있었고, 그때 storage를 담당하던 팀원분께서 엄청 고생을 많이 하시고 해당 url을 확인하는 방법을 찾아내서 알려주신 적이 있었다.

그래서 아래 GET URL 을 통해 주소를 확인해보니 다음과 같았다.

(저 버튼을 클릭하면 url 주소가 복사되므로 해당 url을 주소창에 넣어서 확인해보자..)

https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/classImages/uploads/b06db7ba-911e-4f4f-993e-147d47118307_143777_149131_434.jpg

https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/uploads/b06db7ba-911e-4f4f-993e-147d47118307_143777_149131_434.jpg

얼핏 보기엔 두 url 주소가 비슷해보여서 같은 주소가 맞는데 왜 값이 이미지를 못 불러오지? 라고 생각할 수 있는데… 진짜 자~알 뜯어보니 두 주소가 다른 걸 확인할 수 있었다.

→ 바로 public/classImages/uploadspublic/uploads 이 부분이었다.. 처음부터 url path 설정을 해줄 때 ‘classImages’(bucket name) 를 추가해주지 않았고, 제대로된 경로가 아니므로 이미지 파일을 찾을 수 없다고 뜨고 있었다.

  // supabase storage에 등록한 이미지 업로드
  const uploadFile = async (file: File) => {
    const cleanName = cleanFileName(file.name);
    const filePath = `uploads/${uuidv4()}_${cleanName}`;
    const { data, error } = await supabase.storage.from('classImages').upload(filePath, file);
    if (error) {
      console.error('파일 업로드 실패:', error);
      return null;
    } else {
      const url = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/${data.path}`;
      return url;
    }
  };

 

문제 해결) 정확한 경로로 url 접근하기

🔥 제대로된 url 주소만 따로 보면 다음과 같다.

const url = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/classImages/${data.path}`;

여기서 url 주소를 만들어주는 부분이 있는데,

  1. ${process.env.NEXT_PUBLIC_SUPABASE_URL} : 초기 설정한 supabase의 url 주소
  2. /storage/v1/object/public : supabase 내에서 storage에 접근하는 주소
  3. /classImages : storage bucket 이름을 작성
  4. /${data.path} : 내가 설정한 filePath를 가장 마지막에 붙여준다.
const filePath = uploads/${uuidv4()}_${cleanName};