JS getirme API'sı ile nasıl dosya yüklerim?


171

Hala kafamı etrafına sarmaya çalışıyorum.

Ben kullanıcı dosya girişi ile dosya (veya birden fazla) seçin yapabilirsiniz:

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

Ve submitolayı kullanarak yakalayabilirim <fill in your event handler here>. Ama bir kez yaptıktan sonra, dosyayı kullanarak nasıl gönderirim fetch?

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

1
Resmi belge bazı cevaplar başarısız olduktan sonra benim için çalışıyor: developer.mozilla.org/en-US/docs/Web/API/Fetch_API/… , bir şey onaylayabilir: 1. FromData'da wrap dosyası gerekir; 2. Content-Type: multipart/form-dataistek üstbilgisinde bildirilmesine gerek yok
Spark.Bao

Yanıtlar:


128

Bu, yorumları olan temel bir örnektir. uploadFonksiyon aradığınız budur:

// 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
Bu örnek neden İçerik Türü başlıklarını içeriyor, ancak başka bir yanıt Getir API'sı ile dosya gönderirken bunları atlamayı söylüyor? Hangisi o?
jjrabbit

12
İçerik Türü ayarlamayın. Çalışmasını sağlamak için çok zaman harcadım ve sonra bu makaleyi ayarlamamayı buldum. Ve çalışıyor! muffinman.io/uploading-files-using-fetch-multipart-form-data
Kostiantyn

diyelim ki bu dosyayı Express backend'den nasıl okuyabilirsiniz? Dosya form verisi olarak gönderilmediğinden. Bunun yerine sadece dosya nesnesi olarak gönderilir. Express-fileupload veya multer bu yükleri ayrıştırıyor mu?
sakib11

221

Ben böyle yaptım:

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
Yüklediğiniz FormDatatek şey dosyaysa (orijinal sorunun istediği şey) dosya içeriğini bir nesneye sarmanıza gerek yoktur . parametresi olarak fetchkabul edecektir . input.files[0]body
Klaus

17
Dosya yüklemesini işleyen bir PHP arka ucunuz varsa, dosyayı bir FormData'ya sarmak istersiniz, böylece $ _FILES dizisi düzgün şekilde doldurulur.
ddelrio1986

3
Ayrıca, Google Chrome'un herhangi bir nedenle FormData parçası olmadan istek yükünde dosyayı göstermeyeceğini de fark ettim. Google Chrome'un Ağ panelinde bir hata gibi görünüyor.
ddelrio1986

4
Bu gerçekten doğru cevap olmalı. Diğer yol da çalışıyor ama daha kıvrımlı
jnmandal

/ avatarlarla ne demek istiyorsun? Bazı arka uç API uç noktasına mı başvuruyorsunuz?
Kartikeya Mishra

90

Getirme API'sı ile Dosya göndermek için önemli bir not

content-typeAlma isteği için üstbilgiyi atlamak gerekir . Ardından tarayıcı otomatik olarak Content typeForm Sınırı da dahil olmak üzere başlığı otomatik olarak ekler.

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

Form sınırı, form verileri için sınırlayıcıdır


17
BU! Çok önemli! Kendi içerik türünüzü çok parçalı getirme ile kullanmayın. Kodum neden çalışmıyor hiçbir fikrim yoktu.
Ernestas Stankevičius


1
Bu altın! Ben bunu anlamak değil 1 saat boşa. Bu ipucunu paylaştığınız için teşekkür ederiz
Ashwin Prabhu

1
Faydalı bilgi olmasına rağmen aşağı oy verin, ancak bu OP'nin sorusuna cevap vermeye çalışmaz.
toraritte

3
Bu, MDN Fetch belgelerinde yakalanmayan çok önemli bir bilgidir .
Plasty Grove

36

Birden fazla dosya istiyorsanız, bunu kullanabilirsiniz

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 Ben aynı sorun vardı, çünkü benim API fonksiyonu formData JSON dönüştürmek çalışıyordu. (Ben sadece birine yardımcı şans kapalı yorum)
mp035

19

Tek bir dosya göndermek için tek yapmanız gereken kullanabilirsiniz Filenesneyi inputbireyin .filesdeğeri olarak doğrudan dizideki body:sizin de fetch()başlatıcısı:

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],
});

Bu , Getirme Standardında tanımlanan izin verilen türlerden Filemiras alındığı Blobve Blobbunlardan biri olduğu için çalışır BodyInit.


Bu en basit cevaptır, ancak body: myInput.files[0]istemci tarafında bellekte tutulan bayt miktarına nasıl sebep olur?
bhantol

2
Ben ediyorum beklemek ya ampirik ya delving tarafından içine (yani bu çözüm ile tarayıcı mantıklı dosya akışı ve bunu gerektirecek kadar belleğe okunacak, @bhantol olurdu, ama öğrenmek için benim yolumdan gitmiş değil spec). Onaylamak istiyorsanız, (büyük tarayıcıların her birinde) 50 GB'lık bir dosya veya başka bir şey yüklemek için bu yaklaşımı kullanmayı deneyebilir ve tarayıcınızın çok fazla bellek kullanmaya çalıştığını ve öldürüldüğünü görebilirsiniz.
Mark Amery

Benim için çalışmadı. express-fileuploadistek akışı ayrıştırılamadı. Ama FormDatabir cazibe gibi çalışır.
saldırgan

1
@attacomsian Bir bakışta bana dosya içeren istekleri express-fileuploadişlemek için bir sunucu kütüphanesi gibi multipart/form-datageliyor, bu yüzden evet, bu yaklaşımla uyumlu değil (sadece dosyayı doğrudan istek gövdesi olarak gönderir).
Mark Amery

6

Burada kabul edilen cevap biraz tarihli. Nisan 2020 itibariyle, MDN web sitesinde görülen önerilen bir yaklaşım FormData, içerik türünün kullanılmasını önermektedir ve aynı zamanda ayarlanmasını da istememektedir. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Kolaylık sağlamak için kod snippet'inden alıntı yapıyorum:

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
Kullanmak FormDatayalnızca sunucu form verisi bekliyorsa çalışır. Sunucu POST'un gövdesi olarak ham bir dosya istiyorsa, kabul edilen cevap doğrudur.
Clyde

2

Alex Montoya'nın çoklu dosya giriş öğeleri yaklaşımından atlamak

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

Benim için sorun form verilerini doldurmak için bir response.blob () kullanmak oldu. Görünüşe göre bunu en azından yerel tepki ile yapamazsın, bu yüzden kullanarak sona erdi

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

Getirme bu formatı tanıyor ve dosyayı uri'nin işaret ettiği yere gönderiyor.


0

İşte benim kod:

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
Yorumdan: Merhaba, lütfen kaynak koduyla cevap vermeyin. Çözümünüzün nasıl çalıştığı hakkında güzel bir açıklama sağlamaya çalışın. Bkz: İyi bir cevabı nasıl yazarım? . Thanks
sɐunıɔ ןɐ qɐp
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.