javascript - fetch - Saknas gräns i multipart/form-data POST


Jag vill skicka en new FormData() som body i en POST-förfrågan med fetch API

Operationen ser ut ungefär så här:

var formData = new FormData()
formData.append('myfile', file, 'someFileName.csv')

fetch('https://api.myapp.com', 
  {
    method: 'POST',
    headers: {
      "Content-Type": "multipart/form-data"
    },
    body: formData
  }
)

Problemet här är att gränsen, något som

boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

kommer aldrig in i Content-Type:-huvudet

Det ska se ut så här:

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

När du försöker samma operation med en new XMLHttpRequest(), på detta sätt:

var request = new XMLHttpRequest()
request.open("POST", "https://api.mything.com")
request.withCredentials = true
request.send(formData)

rubrikerna är korrekt inställda

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

Så mina frågor är:

  1. hur får jag fetch att bete sig exakt som XMLHttpRequest i denna situation?
  2. om detta inte är möjligt, varför?

Tack allihopa! Denna community är mer eller mindre anledningen till att jag har professionell framgång.

Svar #1

Lösningen på problemet är att uttryckligen sätta Content-Type till undefined så att din webbläsare eller vilken klient du än använder kan sätta det och lägga till det där gränsvärdet åt dig. Besvikande men sant.

Svar #2

Jag hade samma problem och kunde lösa det genom att exkludera Content-Type egenskapen, vilket tillät webbläsaren att automatiskt upptäcka och ställa in gränsen och innehållstypen.

Din kod blir:

var formData = new FormData()
formData.append('myfile', file, 'someFileName.csv')

fetch('https://api.myapp.com',
  {
    method: 'POST',
    body: formData
  }
)

Svar #3

Jag tog bort "Content-Type" och lade till 'Accept' i HTTP-huvuden och det fungerade för mig. Här är de huvuden jag använde,

'headers': new HttpHeaders({
        // 'Content-Type': undefined,
        'Accept': '*/*',
        'Authorization': 
        "Bearer "+(JSON.parse(sessionStorage.getItem('token')).token),
        'Access-Control-Allow-Origin': this.apiURL,
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
        'Access-Control-Allow-Headers': 'origin,X-Requested-With,content-type,accept',
        'Access-Control-Allow-Credentials': 'true' 

      })

Svar #4

Enligt FormData-dokumentationen bör du inte manuellt ställa in Content-Type-huvudet så att webbläsaren själv ställer in det korrekt:

Varning: När du använder FormData för att skicka POST-förfrågningar med XMLHttpRequest eller Fetch_API med Content-Type multipart/form-data (t.ex. när du laddar upp filer och Blobs till servern), ska du inte uttryckligen ange Content-Type-headern i förfrågan. Att göra det kommer att förhindra att webbläsaren kan sätta Content-Type-headern med gränsuttrycket som den kommer att använda för att avgränsa formulärfält i förfrågningskroppen.

Så om din kod (eller bibliotek/mellansoftware/etc) manuellt har satt Content-Type, har du två sätt att åtgärda det:

  1. skriv om din kod (eller vad du än använder) så att Content-Type inte sätts som standard
  2. sätt Content-Type till undefined eller ta bort det från headers för att låta din webbläsare göra sitt jobb

Svar #5

fetch(url,options)
  1. Om du sätter en sträng som options.body måste du sätta Content-Type i begärans header, annars blir det text/plain som standard.
  2. Om options.body är ett specifikt objekt som let a=new FormData() eller let b=new URLSearchParams(), behöver du inte ställa in Content-Type manuellt. Det kommer att läggas till automatiskt.

    • för a ,det kommer att vara något liknande
    multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

    Som du ser, läggs gränsen till automatiskt.

    • för b är det application/x-www-form-urlencoded;

Relaterade artiklar