이미지 파일을 가진 데이터의 수정 페이지를 만들고 있었다. 이때 데이터를 최초 생성할 땐 input에 File 데이터를 넣어서 FormData로 보내거나 uploadthing과 같은 클라우드 이미지 저장소를 거쳐 이미지 url만 전송하는 등의 작업을 할 수 있을것이다.
이때 이 생성된 데이터를 수정할 떄, 마찬가지로 기존 데이터의 이미지도 있을테다. 그리고 그냥 간단하게, 되진 않겠지만 input 태그에 서버에서 받아온 File을 넣을 순 없나? 라고 생각해봤다. 시도했지만 당연히 되지 않았다.. 흑흐긓... 다른 방법을 찾아봐야지 하기전에 왜 안될까를 정리해보고자 한다.
브라우저는 input type file 요소에 대해서 엄격한 제안을 둔다.
사실 생각해 보면 맞다. 사용자가 의도치 않은 파일이 올려지면 매우 위험할수도 있다...
input.files는 FileList 타입이고 읽기 전용const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
fileInput.files = [file]; // 이건 불가능하다
만약 이 제한이 없으면 아래와 같은 무단 파일 업로드 악성 스크립트같은 것들이 들어가 다음과 같은 상황이 벌어질 수 있는 것이다....
const file = await fetch('private한 주소..').then(res => res.blob());
input.files = [file];
form.submit();
FileList는 생성 자체가 불가능한 설계!new FileList() 같은 생성자도 제공되지 않는다.파일을 다시 업로드하거나 보여주기 위한 목적이라면 다음의 방법을 사용할 수 있다. 물론 여전히 input 태그에 files를 직접 넣지는 못한다.
<img> 또는 <a download> 등으로 사용하기const response = await fetch('이미지 url 정보가 대충 들어갈듯');
const blob = await response.blob();
const url = URL.createObjectURL(blob);
// <img src={url} /> 이렇게 사용
이러할 경우 서버에서 해당 파일을 재사용하거나, 사용자가 새 파일을 업로드하지 않으면 기존 파일 경로 혹은 id 값만 유지해서 전송하는 방식으로 처리하는것이 깔끔하다.
html 스펙 관점에서 볼때, input[type=file]은 오로지 유저 상호작용시에만 작동하며, html 차원에서 유일하게 의도적으로 조작이 불가능하게 설계된 유일한 input이다.