fetch - multipart/form-data POST中缺少边界

Jam*_*mes 38 javascript xmlhttprequest form-data fetch fetch-api

谢谢你的光临.

我想送new FormData()body一个的POST使用请求提取API

操作看起来像这样

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
  }
)
Run Code Online (Sandbox Code Playgroud)

这里的问题是边界,类似的东西

boundary=----WebKitFormBoundaryyEmKNDsBKjB7QEqu

从来没有进入Content-Type:标题

它看起来应该是这样的

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

当你用a尝试"相同"的操作时new XMLHttpRequest(),就像这样

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

标题已正确设置

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

所以我的问题是,

  1. 我如何使这种情况fetch完全像XMLHttpRequest

  2. 如果这不可能,为什么?

谢谢大家!这个社区或多或少是我取得职业成功的原因.

Jam*_*mes 80

该问题的解决方案是明确设置Content-Typeundefined使您的浏览器或您正在使用的任何客户端都可以设置它并在那里为您添加该边界值.令人失望但却是真实的.

  • 使用fetch,我删除了Content-Type标头并且它有效. (12认同)
  • 难以置信的!!我花了几个小时才发现这个!! `删除result.headers ['Content-Type'];`为我工作,谢谢!! (12认同)
  • 不适合我.设置为未定义默认为text/plain. (5认同)
  • 既没有将内容类型设置为未定义,也没有在使用 fetch 进行 POST 之前删除内容类型对我来说...... (3认同)
  • 将 Content-Type 标头设置为 undefined 对我来说似乎是“Content-Type”:请求本身未定义。没有定义它有效。 (2认同)

Aza*_*lin 12

根据FormData 文档,您不应该手动设置Content-Type标头,以便浏览器本身会正确设置它:

警告:当使用 FormData 使用 XMLHttpRequest 或带有 multipart/form-data Content-Type 的 Fetch_API 提交 POST 请求时(例如,将文件和 Blob 上传到服务器时),请勿在请求上显式设置 Content-Type 标头。这样做将阻止浏览器使用边界表达式设置 Content-Type 标头,该边界表达式将用于分隔请求正文中的表单字段。

因此,如果您的代码(或库/中间件/等)手动设置了Content-Type,您有两种方法可以修复它:

  1. Content-Type重写您的代码(或您使用的任何内容)以默认情况下不设置
  2. 设置或删除它,Content-Type让您的浏览器正常工作undefinedheaders


moo*_*der 9

fetch(url,options)
Run Code Online (Sandbox Code Playgroud)
  1. 如果将字符串设置为options.body,则必须设置Content-Typein请求标头,否则它将text/plain默认设置.
  2. 如果options.body是特定对象,let a = new FormData()或者let b = new URLSearchParams(),您不必Content-Type手动设置.它将自动添加.

    • 因为a,它会是这样的

    multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

    如你所见,边界是自动添加的.

    • 因为b,它是application/x-www-form-urlencoded;


And*_*ner 8

我有同样的问题,并且能够通过排除Content-Type属性来修复它,允许浏览器自动检测和设置边界和内容类型。

您的代码变为:

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

fetch('https://api.myapp.com',
  {
    method: 'POST',
    body: formData
  }
)
Run Code Online (Sandbox Code Playgroud)


Nve*_*yan 6

添加headers:{content-type: undefined}浏览器将为您生成一个边界,用于通过流式传输部分上传文件,如果您要添加“多个/表单数据”,则意味着您应该创建流式传输并部分上传文件

所以添加 request.headers = {content-type: undefined} 就可以了


小智 5

我删除了“ Content-Type”,并在HTTP标头中添加了“ Accept”,它对我有用。这是我使用的标题

'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' 

      })
Run Code Online (Sandbox Code Playgroud)

  • 没有其他解决方案对我有用。添加 Accept: */* 标头后,一切都变得非常顺利。 (4认同)