отримати пост із багаточастинними даними форми


86

Я отримую таку URL-адресу:

fetch(url, {
  mode: 'no-cors',
  method: method || null,
  headers: {
    'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
    'Content-Type': 'multipart/form-data'
  },
  body: JSON.stringify(data) || null,
}).then(function(response) {
  console.log(response.status)
  console.log("response");
  console.log(response)
})

Мій API очікує, що дані будуть multipart/form-dataтакими, тому я використовую content-typeцей тип ... Але це дає мені відповідь із кодом стану 400.

Що не так з моїм кодом?

Відповіді:


163

Ви встановлюючи Content-Typeбути multipart/form-data, але потім , використовуючи JSON.stringifyна даному тіло, яке повертається application/json. У вас є невідповідність типу вмісту.

Вам потрібно буде закодувати ваші дані multipart/form-dataзамість json. Зазвичай multipart/form-dataвикористовується під час завантаження файлів і є дещо складнішим, ніж application/x-www-form-urlencoded(що є типовим для HTML-форм).

Специфікацію multipart/form-dataможна знайти в RFC 1867 .

Посібник з подання такого роду даних через javascript див. Тут .

Основна ідея полягає у використанні об’єкта FormData (не підтримується в IE <10):

async function sendData(url, data) {
  const formData  = new FormData();

  for(const name in data) {
    formData.append(name, data[name]);
  }

  const response = await fetch(url, {
    method: 'POST',
    body: formData
  });

  // ...
}

Відповідно до цієї статті переконайтеся, що не встановлено Content-Typeзаголовок. Браузер встановить його для вас, включаючи boundaryпараметр.


const fd = нові FormData (); // Файл для завантаження. fd.append ('файл', fileToUpload); fd.append ('jsondatakey', 'jsondatavalue'); За допомогою цього ви зможете надіслати файл разом з деякими json-даними в тілі.
Джнана

25

Я нещодавно працював з IPFS і працював над цим. Приклад завивки для завантаження файлу IPFS виглядає так:

curl -i -H "Content-Type: multipart/form-data; boundary=CUSTOM" -d $'--CUSTOM\r\nContent-Type: multipart/octet-stream\r\nContent-Disposition: file; filename="test"\r\n\r\nHello World!\n--CUSTOM--' "http://localhost:5001/api/v0/add"

Основна ідея полягає в тому, що кожна частина (розділена на рядок у boundaryз --) має власні заголовки (наприклад, Content-Typeу другій частині). FormDataОб’єкт керує всім цим для вас, тож це кращий спосіб досягти наших цілей.

Це означає, щоб отримати API так:

const formData = new FormData()
formData.append('blob', new Blob(['Hello World!\n']), 'test')

fetch('http://localhost:5001/api/v0/add', {
  method: 'POST',
  body: formData
})
.then(r => r.json())
.then(data => {
  console.log(data)
})

16
Зверніть увагу на вищезазначений метод, НЕ надайте заголовки, якщо ви робите це за допомогою FormData, оскільки це перекриє межу, яку встановлено автоматично.
Matt Pengelly

1
Дякую @MattPengelly! Як тоді встановити власні заголовки, такі як Авторизація?
Драгош

7
@DragosStrugar ви все ще можете встановлювати заголовки (авторизація включена), просто не встановлюйте вручну заголовок Content-Type, якщо ви використовуєте FormData.
RobertMcReed

2
НЕ постачайте заголовки з "Content-Type", якщо він використовує FormData.
caot,

1
У прикладі завитки вам це потрібно. У FormDataнаведеному прикладі він вам не потрібен, оскільки браузер надсилає вам цей заголовок, а також керує усіма мімами MIME, що і є суттю цього рішення.
споживач
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.