我的代码:

fetch("api/xxx", {
    body: new FormData(document.getElementById("form")),
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        // "Content-Type": "multipart/form-data",
    },
    method: "post",
}

我尝试使用fetch api发布我的表单,它发送的正文是这样的:

-----------------------------114782935826962
Content-Disposition: form-data; name="email"

test@example.com
-----------------------------114782935826962
Content-Disposition: form-data; name="password"

pw
-----------------------------114782935826962--

(我不知道为什么每次发送的时候boundary里的数字都会变…)

我想用“Content-Type”:“application/x-www-form-urlencoded”发送数据,我该怎么做?或者如果我必须处理它,我如何解码控制器中的数据?


请回答我的问题,我知道我能做到:

fetch("api/xxx", {
    body: "email=test@example.com&password=pw",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    },
    method: "post",
}

我想要的是像$(“#form”).serialize()在jQuery (w/o使用jQuery)或解码控制器中的多部分/表单数据的方法。谢谢你的回答。


当前回答

@ kamilkieczzewski回答是伟大的,如果你是表单数据格式是在表单多部分风格,但如果你需要提交的表单查询参数风格:

如果您希望以使用简单GET提交的方式生成查询参数,也可以将FormData直接传递给URLSearchParams构造函数。

        form = document.querySelector('form')
        const formData = new FormData(form);
        formData["foo"] = "bar";
        const payload = new URLSearchParams(formData)
        fetch(form.action, payload)

其他回答

@ kamilkieczzewski回答是伟大的,如果你是表单数据格式是在表单多部分风格,但如果你需要提交的表单查询参数风格:

如果您希望以使用简单GET提交的方式生成查询参数,也可以将FormData直接传递给URLSearchParams构造函数。

        form = document.querySelector('form')
        const formData = new FormData(form);
        formData["foo"] = "bar";
        const payload = new URLSearchParams(formData)
        fetch(form.action, payload)

你可以将body设置为URLSearchParams的一个实例,并将查询字符串作为参数传递

fetch("/path/to/server", {
  method:"POST"
, body:new URLSearchParams("email=test@example.com&password=pw")
})

document.forms[0]。Onsubmit = async(e) => { e.preventDefault (); const params = new URLSearchParams([…]新FormData (e。target) .entries ())); // fetch("/path/to/server", {method:"POST", body:params}) const response =等待新的响应(params).text(); console.log(响应); } < >形式 <input name="email" value="test@example.com"> <input name="password" value="pw"> < input type = " submit " > > < /形式

MDN上有一些说明,浏览器将自动处理Content-Type:

如果字典中没有设置内容类型头,请求也会自动设置一个内容类型头。

所以当我们发送一个取回请求时,我们不需要指定'content-type'。

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.then(result => {
  console.log('Success:', result);
})
.catch(error => {
  console.error('Error:', error);
});

如果在头文件中设置content-type。浏览器将不会尝试分割请求有效负载中的表单数据。

我使用fathcer来处理FormData,与XHR的行为相同。

import { formData } from '@fatcherjs/middleware-form-data';
import { json } from '@fatcherjs/middleware-json';
import { fatcher } from 'fatcher';

fatcher({
    url: '/bar/foo',
    middlewares: [json(), formData()],
    method: 'PUT',
    payload: {
        bar: 'foo',
        file: new File()
    },
    headers: {
        'Content-Type': 'multipart/form-data',
    },
})
    .then(res => {
        console.log(res);
    })
    .catch(err => {
        console.error(error);
    });

Content-Type: " multipart /form-data"

const formData = new FormData(document.getElementById("form"))

fetch("http://localhost:8000/auth/token", {
  method: "POST",
  body: formData,
  headers: {
    "Content-Type": "multipart/form-data"
  }
})

Content-Type: "application/x-www-form-urlencoded"

const formData = new URLSearchParams(new FormData(document.getElementById("form")))

fetch("http://localhost:8000/auth/token", {
  method: "POST",
  body: formData,
  headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  }
})

引用FormData上的MDN(重点是我的):

FormData接口提供了一种方法,可以轻松地构造一组表示表单字段及其值的键/值对,然后可以使用XMLHttpRequest.send()方法轻松地发送这些字段。它使用与编码类型设置为“multipart/form-data”的表单相同的格式。

所以当你使用FormData时,你就把自己锁在了multipart/form-data中。没有办法将FormData对象作为主体发送,而不以multipart/form-data格式发送数据。

如果你想要以application/x-www-form-urlencoded的形式发送数据,你必须将主体指定为url编码的字符串,或者传递一个URLSearchParams对象。不幸的是,后者不能直接从表单元素初始化。如果你不想自己遍历你的表单元素(你可以使用HTMLFormElement.elements),你也可以从FormData对象创建一个URLSearchParams对象:

const data = new URLSearchParams();
for (const pair of new FormData(formElement)) {
    data.append(pair[0], pair[1]);
}

fetch(url, {
    method: 'post',
    body: data,
})
.then(…);

注意,您不需要自己指定Content-Type标头。


正如monk-time在注释中所指出的,你也可以创建URLSearchParams并直接传递FormData对象,而不是在循环中追加值:

const data = new URLSearchParams(new FormData(formElement));

不过,在浏览器中仍然有一些实验性的支持,所以在使用它之前一定要进行适当的测试。