JS fetch API로 파일을 어떻게 업로드합니까?


170

나는 여전히 내 머리를 감싸려고합니다.

사용자가 파일 입력으로 파일 (또는 여러 개)을 선택할 수 있습니다.

<form>
  <div>
    <label>Select file to upload</label>
    <input type="file">
  </div>
  <button type="submit">Convert</button>
</form>

그리고를 submit사용 하여 이벤트를 잡을 수 있습니다 <fill in your event handler here>. 그러나 일단 내가 한 다음을 사용하여 파일을 보내려면 어떻게해야 fetch합니까?

fetch('/files', {
  method: 'post',
  // what goes here? What is the "body" for this? content-type header?
}).then(/* whatever */);

1
몇 가지 답변을 시도하는 후 나에 대한 공식 문서 작업 실패 : developer.mozilla.org/en-US/docs/Web/API/Fetch_API/...는 , 뭔가 확인할 수 있습니다 FromData 1. 필요 랩 파일을; 2. Content-Type: multipart/form-data요청 헤더 에 선언 할 필요가 없습니다
Spark.Bao

답변:


127

주석이 포함 된 기본 예입니다. upload기능은 당신이 찾고있는 것입니다 :

// Select your input type file and store it in a variable
const input = document.getElementById('fileinput');

// This will upload the file after having read it
const upload = (file) => {
  fetch('http://www.example.net', { // Your POST endpoint
    method: 'POST',
    headers: {
      // Content-Type may need to be completely **omitted**
      // or you may need something
      "Content-Type": "You will perhaps need to define a content-type here"
    },
    body: file // This is your file object
  }).then(
    response => response.json() // if the response is a JSON object
  ).then(
    success => console.log(success) // Handle the success response object
  ).catch(
    error => console.log(error) // Handle the error response object
  );
};

// Event handler executed when a file is selected
const onSelectFile = () => upload(input.files[0]);

// Add a listener on your input
// It will be triggered when a file will be selected
input.addEventListener('change', onSelectFile, false);

8
이 예제에 Content-Type 헤더가 포함되어 있지만 Fetch API를 사용하여 파일을 보낼 때 다른 답변에서 헤더를 생략하라는 이유는 무엇입니까? 어떤거야?
jjrabbit

12
Content-Type을 설정하지 마십시오. 나는 그것을 작동 시키려고 많은 시간을 보냈다. 그리고 작동합니다! muffinman.io/uploading-files-using-fetch-multipart-form-data
Kostiantyn

Express 백엔드에서이 파일을 어떻게 읽습니까? 파일이 양식 데이터로 전송되지 않기 때문에. 대신 파일 객체로 전송됩니다. express-fileupload 또는 multer가 그러한 페이로드를 구문 분석합니까?
sakib11

221

나는 이렇게했다 :

var input = document.querySelector('input[type="file"]')

var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')

fetch('/avatars', {
  method: 'POST',
  body: data
})

16
FormData업로드하는 모든 파일이 파일 (원래 질문에서 원하는 것) 인 경우 파일 내용을 객체 로 감싸지 않아도됩니다 . 위의 매개 변수 로 fetch허용 됩니다. input.files[0]body
클라우스

17
파일 업로드를 처리하는 PHP 백엔드가있는 경우 $ _FILES 배열이 올바르게 채워지도록 파일을 FormData로 랩핑해야합니다.
ddelrio1986

2
또한 Chrome이 어떤 이유로 FormData 부분이 없으면 요청 페이로드에 파일을 표시하지 않는다는 것을 알았습니다. Chrome의 네트워크 패널에 버그가있는 것 같습니다.
ddelrio1986

4
이것은 정답이어야합니다. 다른 방법도 작동하지만 더 복잡합니다
jnmandal

/ avatars은 무슨 뜻인가요? 백엔드 API 엔드 포인트를 언급하고 있습니까?
Kartikeya Mishra

90

Fetch API로 파일을 전송하기위한 중요한 참고 사항

content-typeFetch 요청을 위해 헤더 를 생략해야합니다 . 그런 다음 브라우저는 Content type다음과 같은 Form Boundary를 포함하여 헤더를 자동으로 추가합니다.

Content-Type: multipart/form-data; boundary=—-WebKitFormBoundaryfgtsKTYLsT7PNUVD

양식 경계는 양식 데이터의 구분 기호입니다.


17
이! 매우 중요! 멀티 파트에서 가져 오기와 함께 고유 한 컨텐츠 유형을 사용하지 마십시오. 내 코드가 왜 작동하지 않는지 전혀 몰랐습니다.
Ernestas Stankevičius


1
이것은 금입니다! 나는 이것을 이해하지 못하고 1 시간을 낭비했다. 이 팁을 공유해 주셔서 감사합니다
Ashwin Prabhu

1
유용한 정보인데도 OP의 질문에 대한 답변을 시도하지 않기 때문에 Downvote.
toraritte

3
이것은 MDN 가져 오기 문서 에서 캡처되지 않은 매우 중요한 정보입니다 .
Plasty Grove

36

여러 파일을 원한다면 이것을 사용할 수 있습니다

var input = document.querySelector('input[type="file"]')

var data = new FormData()
for (const file of input.files) {
  data.append('files',file,file.name)
}

fetch('/avatars', {
  method: 'POST',
  body: data
})

@ Saly3301 같은 문제가 발생했습니다. API 함수가 formData를 JSON으로 변환하려고했기 때문입니다. (나는 누군가를 도울 수있는 오프 기회에 대해서만 언급했다)
mp035

19

하나의 파일을 제출하려면, 당신은 단순히 사용할 수 있습니다 File으로부터 객체 input.files값으로 직접 배열 body:당신의 fetch()초기화 :

const myInput = document.getElementById('my-input');

// Later, perhaps in a form 'submit' handler or the input's 'change' handler:
fetch('https://example.com/some_endpoint', {
  method: 'POST',
  body: myInput.files[0],
});

이는 작동 File상속을에서 Blob, 그리고 Blob허용 중 하나입니다 BodyInit페치 표준에 정의 된 유형.


이것은 가장 간단한 대답이지만 body: myInput.files[0]클라이언트 측의 메모리에 바이트 크기 가 어떻게 발생합니까?
bhantol

2
난 것 기대 중 경험적으로 또는 탐구에 의해로 (즉,이 솔루션 브라우저가 재치있는 파일을 스트리밍하지 그것을 필요로하기에 충분한 메모리로 읽을 수 있도록, @bhantol 것입니다,하지만 난 알아 내 방식의 사라하지 않은 사양). 확인하고 싶다면이 방법을 사용하여 (각 주요 브라우저에서) 50GB 파일 또는 무언가를 업로드하고 브라우저가 너무 많은 메모리를 사용하려고 시도하고 종료되는지 확인할 수 있습니다.
Mark Amery

나를 위해 일하지 않았다. express-fileupload요청 스트림을 구문 분석하지 못했습니다. 그러나 FormData매력처럼 작동합니다.
attacomsian

1
@attacomsian 한 눈에 파일을 포함 express-fileupload하는 multipart/form-data요청 을 처리하는 서버 측 라이브러리 처럼 보입니다 . 그래서이 방법 (파일을 요청 본문으로 직접 보내는)과 호환되지 않습니다.
Mark Amery

6

여기에 허용되는 답변은 약간 날짜가 있습니다. 2020 년 4 월 현재 MDN 웹 사이트에서 볼 수있는 권장 방법은 사용을 제안 FormData하고 내용 유형을 설정하도록 요청하지 않습니다. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

편의상 코드 스 니펫을 인용하고 있습니다.

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then((response) => response.json())
.then((result) => {
  console.log('Success:', result);
})
.catch((error) => {
  console.error('Error:', error);
});

1
FormData서버가 양식 데이터를 예상하는 경우에만 사용 이 작동합니다. 서버가 원시 파일을 POST의 본문으로 원하는 경우 승인 된 답변이 맞습니다.
클라이드

2

여러 파일 입력 요소에 대한 Alex Montoya의 접근 방식에서 벗어나기

const inputFiles = document.querySelectorAll('input[type="file"]');
const formData = new FormData();

for (const file of inputFiles) {
    formData.append(file.name, file.files[0]);
}

fetch(url, {
    method: 'POST',
    body: formData })

1

나에게 문제는 response.blob ()을 사용하여 양식 데이터를 채우는 것입니다. 분명히 당신은 적어도 기본 반응으로 그렇게 할 수 없으므로 결국에는

data.append('fileData', {
  uri : pickerResponse.uri,
  type: pickerResponse.type,
  name: pickerResponse.fileName
 });

Fetch는 해당 형식을 인식하고 URI가 가리키는 파일을 보내는 것으로 보입니다.


0

내 코드는 다음과 같습니다.

html :

const upload = (file) => {
    console.log(file);

    

    fetch('http://localhost:8080/files/uploadFile', { 
    method: 'POST',
    // headers: {
    //   //"Content-Disposition": "attachment; name='file'; filename='xml2.txt'",
    //   "Content-Type": "multipart/form-data; boundary=BbC04y " //"multipart/mixed;boundary=gc0p4Jq0M2Yt08jU534c0p" //  ή // multipart/form-data 
    // },
    body: file // This is your file object
  }).then(
    response => response.json() // if the response is a JSON object
  ).then(
    success => console.log(success) // Handle the success response object
  ).catch(
    error => console.log(error) // Handle the error response object
  );

  //cvForm.submit();
};

const onSelectFile = () => upload(uploadCvInput.files[0]);

uploadCvInput.addEventListener('change', onSelectFile, false);
<form id="cv_form" style="display: none;"
										enctype="multipart/form-data">
										<input id="uploadCV" type="file" name="file"/>
										<button type="submit" id="upload_btn">upload</button>
</form>
<ul class="dropdown-menu">
<li class="nav-item"><a class="nav-link" href="#" id="upload">UPLOAD CV</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="download">DOWNLOAD CV</a></li>
</ul>


1
리뷰에서 : 안녕하세요, 소스 코드로 대답하지 마십시오. 솔루션 작동 방식에 대한 좋은 설명을 제공하십시오. 참조 : 좋은 답변을 작성하려면 어떻게합니까? . 감사합니다
sɐunıɔ ןɐ qɐp
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.