React.js 와 Vue.js 에서 파일 받기

React.js 와 Vue.js 에서 파일 받기

앞서,

이 글은 아래와 같은 환경에서 작업된 글이에요.
혹시라도 버전이 다르면 문제가 생길 수 있으니 조심해주세요.

  • 운영체제: MacOS Catalina 10.15.2
  • Node.js: v12.14.0
  • Vue: 2.6.10
  • Axios: 0.19.0

프로젝트에서 데이터를 엑셀로 변환하여 다운로드 받을 수 있는 기능이 필요했어요. 만약 특별한 기능없이 다운로드만 진행하게 된다면 새 창을 띄워서 다운로드를 받으면 되지만 배열로 된 데이터를 서버에 요청해서 필요한 정보만 가져오도록 기능을 만들어야 했기 때문에 GET보다 POST 방식을 사용해야 했어요. 그러다보니 새 창을 띄워서 파일을 받기는 조금 어려웠어요.


1. 캐찹 소스(FULL SOURCE)

저의 설명보다 소스를 필요하실 분들이 더 많을 것 같아서 먼저 소스를 올려요. 설명이 필요하신 분들만 내려서 설명을 확인하시면 될 것 같아요.

const { data } = await Axios.post(
  `/v1/logs/generate`,
  { items: _.map(state.displayedLogs, 'idx') },
  { responseType: 'blob', withCredentials: true }
);

const objectUrl = window.URL.createObjectURL(data);
const linkElement = document.createElement('a');
linkElement.href = objectUrl;
linkElement.setAttribute(
  'download',
  `log-${moment().format('YYYY-MM-DD-HH:mm:ss')}.xlsx`
);

document.body.appendChild(linkElement);
linkElement.click();

2. Axios 요청

일단 Axios 요청은 아래와 같이 했어요.

해당 부분은 특별하게 중요하지 않아요. Axios로 파일을 받아오기만 하면 되요. GET, POST … 아무거나 상관없어요.

GET 요청을 사용한다면,

const { data } = await Axios.get(
  `/v1/logs/generate`,
  { responseType: 'blob', withCredentials: true }
);

POST 요청을 사용한다면,

const { data } = await Axios.post(
  `/v1/logs/generate`,
  { items: _.map(state.displayedLogs, 'idx') },
  { responseType: 'blob', withCredentials: true }
); 

저의 경우는 각 로그의 아이디를 모두 가져와 서버에 요청하여 엑셀(XlSX)을 생성하는 것이 필요해서, Lodash(언더바가 lodash)를 통해 state.displayedLogs 배열의 모든 idx를 가져와서 그걸 body에 담았어요. 이외에 옵션으로는 크레덴셜, 리스폰스 타입을 넣어줬어요.

중요! 다른 것은 상관없지만 responseType은 반드시 blob 여야 해요.

await 으로 대기하게 만들었지만 굳이 이렇게 안하고 아래처럼 then 콜백 함수를 사용해서 데이터를 받아도 상관없어요.

Axios.post(
  ... 옵션 동일
).then(({ data }) => {
  ... 앞으로 소스를 넣을 곳
}); 

3. 오브젝트 URL 생성

아까 위에서 받은 데이터는 오브젝트라는 타입으로 리턴이 될 거에요. 하지만 href에 오브젝트라는 타입 자체를 넣을 수 없으니, 이걸 URL로 생성할거에요.

const objectUrl = window.URL.createObjectURL(data);

URL을 생성했어요. 이제 리턴된 데이터를 확인하면 아마 아래랑 비슷하게 나올거에요.

blob:http://danal.me/d6aeac44-767d-42b9-a4a9-8ee5f8885696

이렇게 하면 blob URL이 생성되요. 오브젝트 URL을 생성시킨 세션(브라우저)에서만 작동되요. 남한테는 공유가 안되는 임시 주소같은 느낌이라고 생각하시면 편할 것 같아요.


4. 엘레먼트 생성

이제 URL을 열어야 해요. 여는 방식이 다양하지만 저의 경우는 마지막에 element를 추가해서 클릭 효과를 발동함으로써 다운로드가 되게 만들거에요. 이외에 새 창으로 넘겨서 다운로드해도 되고 버튼 클릭시에도 사용 가능하다는 점 참고바래요.

const linkElement = document.createElement('a');
linkElement.href = objectUrl;
linkElement.setAttribute(
  'download',
  `log-${moment().format('YYYY-MM-DD-HH:mm:ss')}.xlsx`
);

document.body.appendChild(linkElement);

element를 생성해서 해당 elementhref 속성과 download 속성까지 넣어놨어요. download 속성에 파일을 입력하면 파일 이름이 지정되요. 마지막 줄에는 document body에 추가해요. 그럼 아마 html 끝에 a 태그가 들어갔다는 것을 확인할 수 있을거에요.


5. 임의 클릭

다했어요. 이제 아래처럼 클릭을 한 것과 같은 효과를 주는 함수를 사용해서 다운로드를 받으면 되요. 쉽죠? 

linkElement.click();

References

How to Download File using Axios Vue JS?
[JS] Blob와 Blob URL
Join the discussion

반가워요.

Node.js, Python, Java, C#
HTML, JavaScript
( BACKEND – FRONTEND )

중졸, 고졸 모두 끝내고
별짓 다해보는 학생입니다. 😀