ฉันจะโพสต์ด้วยข้อมูลฟอร์มหลายส่วนโดยใช้การดึงข้อมูลได้อย่างไร


90

ฉันกำลังดึง 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

รหัสของฉันผิดอะไร

คำตอบ:


175

คุณกำลังตั้งค่า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

สำหรับคำแนะนำเกี่ยวกับวิธีการที่จะส่งชนิดของข้อมูลที่ผ่านทางจาวาสคริปต์ให้ดูที่นี่

แนวคิดพื้นฐานคือการใช้วัตถุ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 ในร่างกายได้
Jnana

จะทำอย่างไรหากต้องการการอนุญาต
DAVE

26

เมื่อเร็ว ๆ นี้ฉันทำงานกับ IPFS และได้ดำเนินการนี้ ตัวอย่าง curl สำหรับ 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)
})

17
หมายเหตุเกี่ยวกับวิธีการข้างต้นอย่าใส่ส่วนหัวหากคุณใช้ FormData เพราะจะแทนที่ขอบเขตที่กำหนดโดยอัตโนมัติ
Matt Pengelly

1
ขอบคุณ @MattPengelly! จะตั้งค่าส่วนหัวแบบกำหนดเองเช่น Authorization ได้อย่างไร?
Dragos Strugar

7
@DragosStrugar คุณยังคงสามารถตั้งค่าส่วนหัวได้ (รวมการอนุญาต) แต่อย่าตั้งค่าส่วนหัวประเภทเนื้อหาด้วยตนเองหากคุณใช้ FormData
RobertMcReed

3
อย่าใส่ส่วนหัวด้วย 'Content-Type' หากใช้ FormData
caot

1
ในตัวอย่าง curl คุณต้องใช้ ในFormDataตัวอย่างคุณไม่จำเป็นต้องใช้เนื่องจากเบราว์เซอร์ส่งส่วนหัวนั้นให้คุณและยังจัดการขอบเขตละครใบ้ทั้งหมดซึ่งเป็นประเด็นของโซลูชันนี้
konsumer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.