기묘한 파일 다운 이야기

짱유경·2021년 4월 15일
3
post-thumbnail

🔥 엑셀 파일이 안열리는 문제

엑셀 다운로드 기능이 프로젝트에 있어 만들던 도중, 분명 제대로 나는 만들었는데..! postman에서도 잘 저장이 되는데...! 위와 같이 "파일명"에 문제가 있습니다. 이 통합 문서의 내용을 최대한 복구하시겠습니까?블라블라블라... 라는 문제가 발생했었다. 처음에는 인코딩 문제인 줄 알고 blob객체에 utf-8속성을 추가했지만, 여전히 파일은 손상되어서 다운받아졌다.

문제의 코드 🔽

const res = await apiClient.post(
        `/api/${location.pathname}/exceldownload`,
        {
          responseType: "arraybuffer",
        }
);
const file = new Blob([res.data], {
  type: "text/xlsx;charset=utf-8",
});
FileSaver.saveAs(file, "test.xlsx");

분명 이상한 부분은 없는 것 같은데 계속해서 파일이 제대로 다운받아지지 않았다. 그래서 머리를 싸매고 고민하다가 헤더에 Content-type을 넣어보면 어떨까 해서 같이 보내줬다.

🦾 해결

const axiosConfig = {
    headers: {
      "Content-type":
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8",
    },
};
  
const res = await apiClient.post(
        `/api/${location.pathname}/exceldownload`,
        axiosConfig,
        {
          responseType: "arraybuffer",
        }
);

const file = new Blob([res.data], {
  type: "text/xlsx;charset=utf-8",
});
FileSaver.saveAs(file, "test.xlsx");

header에 "Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8" 을 같이 보내준 코드. 그러더니 놀랍도록 잘 다운받아지고 잘 열렸다.... .

엑셀 파일 뿐만 아니라 pdf파일과 wav파일 듣기 또한 파일이 깨져서 다운받아졌는데, 위와같이 Content-type을 제대로 명시해주니 정상적으로 다운이 받아졌다.

Content-type을 붙여주면 파일이 잘 열릴까? 궁금해서 찾아봤는데 아래와 같은 문서가 있었다.

MIME 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘입니다: 웹에서 파일의 확장자는 별 의미가 없습니다. 그러므로, 각 문서와 함께 올바른 MIME 타입을 전송하도록, 서버가 정확히 설정하는 것이 중요합니다. 브라우저들은 리소스를 내려받았을 때 해야 할 기본 동작이 무엇인지를 결정하기 위해 대게 MIME 타입을 사용합니다.

이외에도 몇가지 자료를 더 찾아봤는데, 이해한 결과 서버와 브라우저에서 통신 시 상호간의 인식을 돕기 위해 정확한 MIME타입을 명시해줘야 한다는 걸로 결론이 났다. (혹시라도 더욱 정확한 정보를 아는 분이라면, 댓글로 알려주시면 감사하겠습니다..🙇‍♀️)

✨ 보너스 - 리액트에서 엑셀 다운로드 하기

🎫 외부 라이브러리 없이 사용하기

위의 코드는 FilseSaver 를 사용해서 다운로드를 처리했다. 하지만 <a>태그나 window.open를 사용해서 라이브러리를 사용하지 않고 다운로드를 처리할 수도 있다😊

const url = window.URL.createObjectURL(
   new Blob([res.data], { type: res.headers["content-type"] })
 );
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "exel_name.xlsx");
document.body.appendChild(link);
link.click()

✨ 보너스2 - content disposition 값 접근하기

기본적으로 클라이언트에서 res.headers와 같은 방식으로 접근 시 보이는 헤더 값은 아래와 같다.
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
이때 백엔드에서 접근하려는 헤더 값에 exposeHeaders 키워드를 넣어주면 클라이언트에서도 위의 값 외에도 접근이 가능해진다. content disposition은 파일명을 지정해주는 헤더인데, exposeHeaders를 통해 클라이언트에서도 해당 헤더에 접근이 가능해진다.

🎉 마치며

나와 같이 리액트에서 엑셀 다운로드를 구현하다가 해당 문제에서 걸린 분들에게 도움이 되면 좋겠다.. 또, http에 대한 공부를 더욱 열심히 해야겠다고 느껴졌다. 미뤄뒀던 강의를 결제하러 수강바구니에 들어갔다.

혹시라도 틀린 정보가 있다면 댓글로 남겨주세요 ! 읽어주셔서 감사합니다🙇‍♀️

0개의 댓글