tìm nạp bài đăng với dữ liệu biểu mẫu nhiều phần


86

Tôi đang tìm nạp một URL như thế này:

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 của tôi mong muốn dữ liệu là của multipart/form-datanên tôi đang sử dụng content-typeloại này ... Nhưng nó đang cho tôi phản hồi với mã trạng thái 400.

Có gì sai với mã của tôi?

Câu trả lời:


164

Bạn đang thiết lập Content-Typelà có multipart/form-data, nhưng sau đó sử dụng JSON.stringifytrên dữ liệu body, dữ liệu này sẽ trả về application/json. Bạn có loại nội dung không khớp.

Bạn sẽ cần phải mã hóa dữ liệu của mình multipart/form-datathay vì json. Thường multipart/form-datađược sử dụng khi tải lên tệp và phức tạp hơn một chút so với application/x-www-form-urlencoded(là mặc định cho các biểu mẫu HTML).

Thông số kỹ thuật cho multipart/form-datacó thể được tìm thấy trong RFC 1867 .

Để biết hướng dẫn về cách gửi loại dữ liệu đó qua javascript, hãy xem tại đây .

Ý tưởng cơ bản là sử dụng đối tượng FormData (không được hỗ trợ trong 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
  });

  // ...
}

Mỗi bài viết này chắc chắn không phải để thiết lập các Content-Typetiêu đề. Trình duyệt sẽ đặt nó cho bạn, bao gồm cả boundarytham số.


const fd = new FormData (); // Tệp để tải lên. fd.append ('file', fileToUpload); fd.append ('jsondatakey', 'jsondatavalue'); Với điều này, bạn sẽ có thể gửi tệp cùng với một số dữ liệu json trong nội dung.
Jnana

25

Gần đây tôi đã làm việc với IPFS và đã giải quyết vấn đề này. Một ví dụ cuộn tròn cho IPFS để tải lên tệp trông như sau:

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"

Ý tưởng cơ bản là mỗi phần (được chia theo chuỗi trong boundaryvới --) có tiêu đề riêng ( Content-Typeví dụ: trong phần thứ hai.) Đối FormDatatượng quản lý tất cả những điều này cho bạn, vì vậy đó là cách tốt hơn để hoàn thành mục tiêu của chúng tôi.

Điều này có nghĩa là tìm nạp API như sau:

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
Lưu ý về phương pháp trên, KHÔNG cung cấp tiêu đề nếu bạn thực hiện bằng FormData vì nó sẽ ghi đè ranh giới được đặt tự động.
Matt Pengelly

1
Cảm ơn @MattPengelly! Sau đó, làm thế nào để đặt các tiêu đề tùy chỉnh như Ủy quyền?
Dragos Strugar

7
@DragosStrugar bạn vẫn có thể đặt tiêu đề (Bao gồm quyền), chỉ cần không đặt tiêu đề Loại-Nội dung theo cách thủ công nếu bạn đang sử dụng Dữ liệu biểu mẫu.
RobertMcReed

2
KHÔNG cung cấp tiêu đề có 'Loại-Nội dung' nếu tiêu đề đó đang sử dụng Dữ liệu biểu mẫu.
caot

1
Trong ví dụ về curl, bạn cần nó. Trong FormDataví dụ, bạn không cần nó, vì trình duyệt gửi tiêu đề đó cho bạn và cũng quản lý tất cả các giới hạn kịch câm, đó là điểm của giải pháp này.
konsumer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.