我的代码:
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--
(我不知道为什么每次发送时边界中的数字都会改变......)
我希望它使用“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",
}
我想要的是 jQuery 中的 $("#form").serialize() (不使用 jQuery)或在控制器中解码 mulitpart/form-data 的方式。不过感谢您的回答。
FormData
有什么问题?
引用 MDN on FormData
(强调我的):
FormData 接口提供了一种方法来轻松构造一组表示表单字段及其值的键/值对,然后可以使用 XMLHttpRequest.send() 方法轻松发送。如果编码类型设置为“multipart/form-data”,它使用与表单相同的格式。
因此,当使用 FormData
时,您会将自己锁定在 multipart/form-data
中。无法将 FormData
对象作为正文发送并且不以 multipart/form-data
格式发送数据。
如果要将数据作为 application/x-www-form-urlencoded
发送,则必须将正文指定为 URL 编码字符串,或传递 URLSearchParams
对象。遗憾的是,后者不能直接从 form
元素初始化。如果您不想自己遍历表单元素(可以使用 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));
不过,这在浏览器中仍有一些实验性支持,因此请确保在使用之前对其进行正确测试。
客户
不要设置内容类型标头。
// Build formData object.
let formData = new FormData();
formData.append('name', 'John');
formData.append('password', 'John123');
fetch("api/SampleData",
{
body: formData,
method: "post"
});
服务器
使用 FromForm
属性来指定绑定源是表单数据。
[Route("api/[controller]")]
public class SampleDataController : Controller
{
[HttpPost]
public IActionResult Create([FromForm]UserDto dto)
{
return Ok();
}
}
public class UserDto
{
public string Name { get; set; }
public string Password { get; set; }
}
application/x-www-form-urlencoded
发送。
Content-Type
并让浏览器自动执行时,它就起作用了。谢谢!
multipart/form-data
,这就是表单数据应该是的!然后您可以在 expressjs 中使用 multer
轻松解析该数据格式。
使用 FormData
和 fetch
抓取和发送数据
fetch(form.action, {method:'post', body: new FormData(form)});
function send(e,form) { fetch(form.action, {method:'post', body: new FormData(form)}); console.log('我们异步发送帖子 (AJAX)'); e.preventDefault(); }
在 chrome 控制台上查看>“提交”之前/之后的网络
fetch
代码 post
<form>
数据,我仍然很惊讶我是如何找到这个的。再见 jQuery。
csrf
代表跨站点请求伪造。
method: 'post'
无效,因为浏览器将使用传递给 FormData
的 form
的方法属性。即使在 form
中未定义方法属性,浏览器也会回退到默认的 GET
方法。
fetch
参数中删除 mehtod:'post'
,您将获得 Request with GET/HEAD method cannot have body.
异常。如果您从上述代码段中的 html 中删除 method="POST"
,则 method:'post'
(在 fetch 参数中)将生效 - 并且浏览器将发送 POST - 我通过修改此代码段并使用 chrome>network 选项卡来检查这一点(所以实际上我们可以删除这是来自 html ......但我会离开它)
您可以将 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([...new FormData(e.target).entries()]); // fetch("/path/to/server", {method:"POST", body:params}) const response = await new Response(params).text();控制台日志(响应); }
Reflect.apply(params.set, params, props)
是一种特别难以理解的方式来表达 params.set(props[0], props[1])
。
Reflect.apply(params.set, params, props)
从这里的角度是可读的。
使用 fetch api,事实证明您不必包含标题“Content-type”:“multipart/form-data”。
所以以下工作:
let formData = new FormData()
formData.append("nameField", fileToSend)
fetch(yourUrlToPost, {
method: "POST",
body: formData
})
请注意,使用 axios 我必须使用内容类型。
👨💻这些可以帮助你:
let formData = new FormData();
formData.append("name", "John");
formData.append("password", "John123");
fetch("https://yourwebhook", {
method: "POST",
mode: "no-cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "form-data"
},
body: formData
});
//router.push("/registro-completado");
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch(function(error) {
console.log("Error getting document:", error);
});
no-cors
和 Content-Type 标头几乎肯定是错误的。
要添加上面的好答案,您还可以避免在 HTML 中明确设置操作并在 javascript 中使用事件处理程序,使用“this”作为创建“FormData”对象的表单
html格式:
<form id="mainForm" class="" novalidate>
<!--Whatever here...-->
</form>
在你的 JS 中:
$("#mainForm").submit(function( event ) {
event.preventDefault();
const formData = new URLSearchParams(new FormData(this));
fetch("http://localhost:8080/your/server",
{ method: 'POST',
mode : 'same-origin',
credentials: 'same-origin' ,
body : formData
})
.then(function(response) {
return response.text()
}).then(function(text) {
//text is the server's response
});
});
@KamilKiełczewski 如果您对表单数据格式采用表单多部分样式没问题,那么答案非常好,但是如果您需要以查询参数样式提交的表单:
如果您想以使用简单 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:FormData”有效,但有类型抱怨,“FormData”也设置了多部分标题。为了使事情更简单,可以使用具有内联构造和手动设置的标题的“body:URLSearchParams”:
function getAccessToken(code) {
return fetch(tokenURL,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
},
body: new URLSearchParams({
'client_id':clientId,
'client_secret':clientSecret,
'code':code,
'grant_type': grantType,
'redirect_uri':'',
'scope':scope
})
}
)
.then(
r => return r.json()
).then(
r => r.access_token
)
}
MDN 上有关于浏览器将自动处理 Content-Type
的说明。
[如果字典中没有设置,请求也会自动设置 Content-Type 头。](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)
所以我们在发送 fetch 请求时不需要指定 '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);
});
要使用 fetch api 发布表单数据,试试这个对我有用的代码 ^_^
function card(fileUri) {
let body = new FormData();
let formData = new FormData();
formData.append('file', fileUri);
fetch("http://X.X.X.X:PORT/upload",
{
body: formData,
method: "post"
});
}
FormData
而不是循环:new URLSearchParams(new FormData(formElement))
URLSearchParams
的构造函数参数是非常 新的,并且支持非常有限。fetch
为您处理会更容易。URLSearchParams
fetch(url, { method: 'post', body: new FormData(form_element), })