회사에서 파일을 업로드,다운,삭제 하는 기능을 종종 접하게 된다.
사실 구현은 어찌저찌 했지만 개념을 정확히 이해하고 있는 것 같지 않다.
뒤돌아서면 까먹는걸 보니ㅠㅠ
이번 기회에 개념을 확실히 알고 자신있게 코드를 다루고싶다.
1. 서버로 파일 업로드시
✅ formData란?
* 브라우저에서 파일을 전송하기 위한 포맷은 formdata 형식
* "multipart/form-data"로 인코딩해야 하는 경우 사용함.
* 폼 데이터에 반복작업할 땐 for...of를 돌면서 append로 하나하나 넣어줘야 한다.
const formData = new FormData();
for(let value of fileList){
formData.append("key", value);
}
* formData를 get요청을 쿼리스트링으로 보낼 경우 URLSearchParams()의 인자로 formData를 넣을 수 있다. (참고자료)
const queryString = new URLSearchParams(new FormData(myForm)).toString()
✅ Content-Type: MIME-Type("multipart/form-data")
axios.post("/api/file-upload", payload, {
headers: {"Content-Type": "multipart/form-data"}
});
1) Content-Type
HTTP 요청시 http body에 들어갈 데이터 타입을 http header에 명시해 줄 수 있는데
그게 바로 content-type을 설정하는 것이다.
2) MIME-Type
그리고 그 content-type의 값으로 MIME-Type을 넣어줘야 한다.
파일을 서버에 전송할 때 파일이 인코딩되어 문자로 전달하게 되는데,
이때 mime-type을 설정하면 해당 형식으로 메세지를 인코딩하여 전송하게 된다.
MIME-Type의 여러 종류 중 하나로 multipart, multipart/form-data가 있다. ※(모든 MIME-Type )
3) mdn의 글을 보면 이런 경고글이 있다.
이는 서버가 content-type에 mime-type을 잘 내려줘야 프론트가 브라우저에서 제대로 파일을 열 수 있다는 말이다. 프론트인 나는 응답 헤더에 content-type이 잘 오는지 확인해야 한다.
✅ multipart/form-data
* json형식으로는 파일 업로드를 처리할 수 없음.
그러나 multipart/form-data는 모든 종류의 파일과 데이터를 보낼 수 있다.
* 두 종류의 데이터를 하나의 Http요청 body에 넣을 때 각 데이터의 종류 구별이 필요할 때 사용되는 타입이다.
(참고자료)
2. 파일 다운시 blob형태로 변환 , 모든 종류의 파일을 다운하기
회사에서 다양한 종류의 파일을 다운받는 기능을 구현하는 미션이 있었다.
처음에 나는 응답받은 값의 파일 종류가 어떤 타입인지 프론트에서도 판별해야 하는게 아닌가 생각했다.
그러나 파일을 여는건 아니고 다운만 하는거니까 서버가 content-type에 mime-type을 제대로 설정만 해주면
프론트는 응답값을 그대로 blob으로 바꿔서 브라우저가 다운만 하게끔 하면 됐었다.
(만약 파일을 뷰어로 열어야 됐고, 그 뷰어 라이브러리가 blob이 아닌 mime-type을 요구했더라면
그땐 서버가 응답한 파일 데이터의 확장자 종류를 content-type을 보고 구별했어야 됐을 것이다.)
✅ blob
axios.get("/api/file-download", { params: payload, responseType: "blob" });
fetch("/api")
.then((res)=>res.blob())
파일 다운을 위한 api 호출 후 서버가 응답한 데이터는 문자열이다. (꿿뚫뛕끽 <- 이런 이상한 문자로 온다.)
때문에 응답 데이터를 blob으로 변환하여 이진데이터를 다룰 수 있게 해야 한다.
<blob호출 결과>
Blob {size: 11111, type: 'application/octet-stream 등등'}
: 단순 객체처럼 보이지만 Blob는 생성자 함수고 인스턴스 객체인 것인 것이다.
blob을 호출하면 서버 응답 데이터가 Blob으로 변환되고, Blob객체에 자동으로 size와 type이 설정된다.
브라우저가 자동으로 응답 헤더에서 해당 정보를 추출해서 size, type을 설정해주는 것이다.
서버 응답에 Content-Length 헤더를 포함하고 있다면, 이 값은 Blob 객체의 size 속성에 할당되고,
Content-Type 헤더의 값은 Blob 객체의 type 속성에 할당된다.
내가 해야하는 파일 다운은 서버가 content-type을 제대로 설정해주면 난 blob으로 변환해서 응답받으면 된다.
그럼 blob객체가 생성되고, 모든 형식의 파일을 다운받을 수 있는 것이다.
✅ blob와 arraybuffer 차이
* 둘다 file data를, 이진 데이터를 다룰 수 있도록 해준다.
* arraybuffer
: 여러개의 바이트를 담고있는 배열이다. ([1바이트, 2바이트, 3바이트, 4바이트 ...] <-여러개의 파일을 담고 있다.)
: js에서 조작하기 쉬운 "배열" 형태로 data를 받을 수 있다.
: zip파일 다운시는 파일이 여러개 있기 떄문에 arraybuffer 형태로 응답받도록 구현하였다.
3.서버에서 응답받은 zip 파일 데이터를 a 태그로 브라우저에서 다운하기
$axios({
url: "/api",
method: "GET",
params: {...},
responseType: "arraybuffer"
})
.then((response) => {
const blobData = response.data;
const blobUrl = URL.createObjectURL(new Blob([blobData]));
const link = document.createElement("a");
link.href = blobUrl;
link.setAttribute("download", shpName);
document.body.appendChild(link);
link.click();
})
✅ new Blob([])
서버 응답 데이터를 arraybuffer로 변환했다.
그치만 브라우저는 Blob객체를 사용해서 이진 데이터를 처리한다.
때문에 ArrayBuffer를 Blob으로 변환해주었다.
✅ window.URL.createObjectURL()
특정 파일이나,blob를 객체 url로 만들때 사용.
파라미터에 blob객체를 넣어 호출하면, 해당 파일 전체 내용을 url 텍스트로 변환한 값이 나온다.
URL.createObjectURL(blob)은 브라우저 메모리에서 Blob 객체를 참조하는 임시 URL을 생성한다.
이 URL은 브라우저 세션 동안만 유효하고, 페이지가 새로고침되면 더 이상 유효하지 않게된다.
✅ a태그의 download 속성
사용자가 링크를 클릭하면 해당 대상 주소로 연결되지 않고, 대신 해당 콘텐츠가 다운된다.
'프론트엔드' 카테고리의 다른 글
외부 CDN의 위험성 (0) | 2024.05.02 |
---|---|
cors와 options메서드 (0) | 2024.04.28 |
charles로 안드로이드 웹뷰 디버깅하기 (0) | 2023.12.09 |
pwa 웹앱 설치하기 - manifest.json (0) | 2023.11.26 |
네이티브 앱, 웹앱, 웹뷰(하이브리드앱) (0) | 2023.11.19 |