본문 바로가기

TIL

[TIL-146] 위코드 53일차: React에서 파일 다운로드하기

sticky

https://deeplify.dev/front-end/markup/position-sticky

 

a와 button

const FileMenu = () => {
  return (
    <div className="fileMenu">
      <button>이름 변경</button>
      <button>
        <a
          href="https://wantubucket1.s3.ap-northeast-2.amazonaws.com/create.png"
          download
        >
          다운로드
        </a>
      </button>
      <button>삭제</button>
    </div>
  );
};
.fileMenu {
  position: absolute;
  left: 50px;
  top: 30px;
  display: flex;
  flex-direction: column;
  width: 100px;
  box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
  border: 1px solid #d1d1d1;

  button {
    all: unset;
    padding: 8px 15px;
    background-color: #ffffff;
    color: black;
    font-size: 14px;

    &:hover {
      color: rgb(105, 105, 105);

      a {
        color: inherit;
      }
    }

    a {
      color: inherit;
    }
  }
}

버튼을 클릭하면 다운로드되게 하려고 button 태그 안에 a 태그를 넣고 download 속성을 부여했다. 하지만 button에 a를 네스팅하는 것은 불필요하며, 스타일 적용이 꼬이게 되었다.

 

 

React 파일 다운로드

<a> download 속성의 문제

Triggering browser download from the frontend is not reliable.
What you should do is, create an endpoint on a server that when called, responds with the correct response headers, thus triggering the browser download.
Frontend code can only do so much. The 'download' attribute for example, might just open the file in a new tab depending on the browser and the type of the file.
The response headers you need to look at are Content-Type and Content-Disposition. You should check this answer for a more detailed explanation on those headers.

* 출처

 

 

 

Blob

블롭은 파일을 이진 형태로 읽을 수 있는 미가공 데이터로 갖고 있는 객체이다.

Blob() 생성자를 사용해 블롭을 생성할 수 있다.

const blob = new Blob(array, options);

 

URL.createObjectURL(Blob)을 호출하면 블롭을 url로 변환할 수 있다. 이 메서드는 File, Blob 객체를 인자로 받아, url을 DOMString에 담아 반환한다. 이 url은 자신이 생성된 창의 document가 사라질 때 무효화되므로 일시적으로 존재한다. 따라서 보안상 안전하다.

 

 

 

다운받기

fetch('https://source.unsplash.com/random/500x500', {
      method: 'GET',
    })
      .then(res => res.blob())
      .then(blob => {
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.setAttribute('download', 'username_이력서.pdf');
        a.click();
      });

무슨 url을 fetch하고, 무슨 response를 받는지, blob()는 뭔지 모르겠어서 이해가 안 됐다.

 

1) 우선 Blob 객체를 만들려면 데이터가 담긴 배열이 필요하다고 했는데 그걸 어디서 구하는가?

=> Blob() 생성자를 쓸 때는, Blob이 아닌 객체와 데이터로 블롭을 생성하고 싶을 때 씀.

2) 다운받을 파일의 링크에 fetch하면 무슨 일이 일어나나?

=> 이런 응답이 옴... fetch는 비동기적으로 리소스에 대한 요청을 보내며, 요청이 가면 Promise 객체가 반환되고, 요청이 완료되면 Promise가 resolve되어 Response 객체가 반환됨. 그 결과로 받은 Response 객체.

https://hogni.tistory.com/142 [JS] 자바스크립트 fetch API 사용하기

3) Blob 생성자도 아니고 blob()은 뭔데?

=> Response 객체에 사용할 수 있는 메서드 중 하나. "A promise that resolves with a Blob"를 반환한다. json()과 비슷한 메서드인 듯.

* https://developer.mozilla.org/en-US/docs/Web/API/Response/blob 참고.

4) 왜 굳이 처음에 갖고 있던 파일 소스(url)를 안 쓰고 복잡하게 DOMString을 만들어다가 a 태그도 따로 만들어서 가짜로 클릭하나?

=> 이거는 아직도 이해가 안 가는 부분. 일단 그냥 url을 a 태그(download 속성)에 링크해놓고 클릭하면 다운로드되지 않고 브라우저에서 해당 파일이 열려서 문제긴 함. 그런데 왜 이 방식으로 하면 다운이 잘 되는 건지??

!) 결론