JSフェッチ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/…、何かが確認できます:1. FromDataにラップファイルが必要です。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

3
また、何らかの理由で、Google ChromeがFormDataパーツなしでリクエストペイロードにファイルを表示しないことにも気付きました。Google Chromeのネットワークパネルのバグのようです。
ddelrio1986

4
これは正解です。逆の方法も機能しますが、より複雑です
jnmandal

/ avatarsとはどういう意味ですか?バックエンドAPIエンドポイントを参照していますか?
Kartikeya Mishra

90

Fetch APIでファイルを送信するための重要な注意事項

content-typeFetchリクエストではヘッダーを省略する必要があります 。次に、ブラウザはContent type次のようなフォーム境界を含むヘッダーを自動的に追加します

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

フォーム境界はフォームデータの区切り文字です


17
この!とても重要です!マルチパートのフェッチで独自のコンテンツタイプを使用しないでください。私のコードが機能しない理由はわかりませんでした。
ErnestasStankevičius18年


1
これは金です!私はこれを理解せずに1時間無駄にした。このヒントを共有してくれてありがとう
Ashwin Prabhu

1
有益な情報ですが、これはOPの質問に答えようとしないため、反対票を投じます。
トラリット

3
これは非常に重要な情報であり、MDN Fetchのドキュメントには記載されていません。
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.filesbody: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のファイルなどをアップロードし、ブラウザがメモリを使いすぎて強制終了されていないかどうかを確認できます。
マークアメリー2018

うまくいきませんでした。express-fileuploadリクエストストリームの解析に失敗しました。しかしFormData、魅力のように機能します。
attacomsian

1
@attacomsian一見すると、ファイルを含むリクエストexpress-fileuploadを処理multipart/form-dataするためのサーバーサイドライブラリのように見えるので、そうです(この方法は、ファイルをリクエストボディとして直接送信するだけです)。
Mark Amery

6

ここで受け入れられた答えは少し時代遅れです。2020年4月の時点で、MDN Webサイトで推奨されているアプローチ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の本文としてrawファイルを必要とする場合、受け入れられた答えは正しいです。
クライド

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()を使用していたことでした。どうやらあなたは少なくともreact nativeではそれを行うことができないので、私は結局使用しました

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.