본문 바로가기
프로그래밍/웹 개발

[React] 파일 다운로드(download) 및 헤더(header) 정보

by 제이콥J 2023. 4. 18.

서버 코드 살펴보기

1. 헤더의 Content-Type을 application/octet-stream으로 설정하기

application/octet-stream은 8비트로 된 데이터라는 뜻으로 response 데이터가 binary 파일이라는 것을 암시합니다.

 

2. Content-Disposition 헤더의 속성값을 attached로 입력하고, filename도 전달하기

Content-Disposition는 Response Body의 콘텐츠를 브라우저에 인라인으로 표시할지 여부를 결정하는 헤더입니다.

속성값에 따른 차이는 아래와 같습니다.

Content-Disposition: inline         // 콘텐츠를 브라우저 화면에 표시합니다.
Content-Disposition: attachment     // 콘텐츠를 다운로드 받습니다.
Content-Disposition: attachment; filename="filename.jpg"  // 파일명을 지정

 

3. 헤더의 Content-Transfer-Encoding 속성값을 binary로 입력하기

Content-Transfer-Encoding 헤더는 binary 메시지를 텍스트 포맷으로 변형시키는 인코딩 방법을 정의합니다.

속성값을 binary로 기재하면 Response 데이터가 binary 데이터라는 것을 암시합니다.

 

response.setContentType("application/octet-stream");

response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName);

response.setHeader("Content-Transfer-Encoding", "binary");

 


프론트엔드 코드 살펴보기

1. axios 요청 시 responseType을 "blob"로 설정하기

Response Data가 binary Blob로 반환되어야 함을 나타내줍니다.

 

  axios({
    method: "get",
    url: `${serverURL}/api/download/`,
    responseType: "blob",
  });

 

*Blob (Binary Large OBject)란?

Blob는 JavaScript에서 binary 데이터를 나타내는데 사용되는 데이터 구조입니다.

이미지, 비디오 등 대용량 데이터를 저장하고 조작할 수 있습니다.

 

Blob 데이터는 Blob 생성자로 만들 수 있으며 다음을 포함한 여러 방법으로 사용할 수 있습니다.

- binary 데이터를 DB 또는 서버에 Blob로 저장합니다.

- 서버에서 binary 데이터를 다운로드하고 사용자를 위한 다운로드 링크를 생성합니다. (2번에서 사용)

- binary 데이터를 기타 다른 형식의로 변환합니다.

 

2. Blob를 통해 다운로드 URL을 생성합니다.

*window.URL.createObjectURL(object) 메소드

: 매개변수 object를 나타내는 URL 문자열을  생성합니다. object에는 파일 또는 Blob 객체가 옵니다.

 

const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));

 

3. Content-Disposition 헤더를 통해 파일명을 추출합니다.

const filename = res.headers["content-disposition"].split("filename=")[1];

 

4. <a>를 만들어 데이터 다운로드를 진행합니다.

DOM 문법을 사용하여 <a>태그를 생성하고, href 속성으로 다운로드 링크를 연결합니다.

 

download 속성값으로 위에서 추출한 filename을 입력합니다.

download 속성이 있어야 해당 링크로 이동하지 않고 파일을 다운로드 받게 됩니다.

 

<a>를 body 태그에 append로 연결하고, click이벤트를 발생시켜 파일을 다운로드 받습니다.

이후 해당 엘리먼트를 제거해줍니다.

 

const link = document.createElement("a");
link.href = downloadUrl;
link.setAttribute("download", filename);
document.body.appendChild(link);
link.click();
link.remove();

 

5. 전체 코드

axios({
  method: "get",
  url: `${serverURL}/api/download/`,
  responseType: "blob",
})
  .then((res) => {
    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
    const filename = res.headers["content-disposition"].split("filename=")[1];
    const link = document.createElement("a");
    link.href = downloadUrl;
    link.setAttribute("download", filename);
    document.body.appendChild(link);
    link.click();
    link.remove();
  })
  .catch((error) => {
    alert("파일 다운로드중 문제가 발생하였습니다.");
  });

 


 

에러핸들링 : Response Header에 Content-Disposition이 없는 경우

개발자도구의 응답 헤더에는 Content-Disposition이 있었습니다.

그러나 Axios의 Response 객체에는 해당 데이터가 담겨있지 않았고, 파일명을 추출하는데 문제가 생겼습니다.

 

원인은 CORS 이슈이며 서버에서 에러핸들링을 해야합니다.

 

// SpringBoot
@CrossOrigin(value = {"*"}, exposedHeaders = {"Content-Disposition"})

 

반응형

댓글