如何使用 multipart/form-data header 和 FormData 使用 fetch POST
How to POST with multipart/form-data header and FormData using fetch
这是一个工作正常的 CURL 示例:
curl -X POST \
<url> \
-H 'authorization: Bearer <token>' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F file=@algorithm.jpg \
-F userId=<userId>
我正在尝试使用 isomorphic-fetch 重现此请求。
我试过以下代码:
const formData = new FormData();
formData.append('file', file);
formData.append('userId', userId);
return fetch(`<url>`, {
method: 'POST',
headers: {
'Content-Length': file.length
'Authorization: Bearer <authorization token>',
'Content-Type': 'multipart/form-data'
},
body: formData
})`
我使用 fs.readFileSync
来生成传递给 FormData
的 file
。
前面的示例 returns 一个 401
HTTP 状态代码(未授权)带有一条错误消息,指出 userId
嵌入到令牌中(通过 header 发送)与从 formData
.
传递的 userId
不匹配
所以我怀疑到达 REST API 的 FormData
没有充分形成。
问题可能与Content-Length
header有关,但我没有找到更好的计算方法(如果我不使用Content-Length
header 我得到一个 411
HTTP 状态代码 Content-Length
header 丢失)。
可能是因为 Content-Length
header 中的值不正确导致失败?
关于失败原因或如何更好地调试它的任何其他建议?
如果需要进一步的信息来澄清这个问题,请直接询问。
更新
我尝试了 form-data 模块,以便使用方法 formData.getLengthSync()
获得正确的 Content-Length
值
但是问题仍然存在(401
错误 HTTP 状态代码响应)。
如果您打开网络检查器,运行 此代码段,并提交表单,您应该会看到 Content-Length
设置正确:
const foo = document.getElementById('foo')
foo.addEventListener('submit', (e) => {
e.preventDefault()
const formData = new FormData(foo)
formData.append('userId', 123)
fetch('//example.com', {
method: 'POST',
body: formData
})
})
<form id="foo">
<input id="file" type="file" name="file"/><br><br>
<button type="submit">Submit</button>
</form>
我的头撞到了类似的墙上,特别是在节点上使用 isomorphic-fetch
到 POST 多部分表单。对我来说关键是找到 .getHeaders()
。请注意 NPM description for form-data
表明它会 "just work" 没有这个,但它似乎没有,至少在节点中没有(我认为浏览器注入 header 东西?)。
// image is a Buffer containing a PNG image
// auth is the authorization token
const form_data = new FormData();
form_data.append("image", png, {
filename: `image.png`,
contentType: 'application/octet-stream',
mimeType: 'application/octet-stream'
});
const headers = Object.assign({
'Accept': 'application/json',
'Authorization': auth,
}, form_data.getHeaders());
try {
const image_res = await fetch(url, {
method: 'POST',
headers: headers,
body: form_data
});
if (!image_res.ok) {
const out = await image_res.json();
console.dir(out);
return;
}
}
catch (e) {
console.error(`Chart image generation exception: ${e}`);
}
这是一个工作正常的 CURL 示例:
curl -X POST \
<url> \
-H 'authorization: Bearer <token>' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F file=@algorithm.jpg \
-F userId=<userId>
我正在尝试使用 isomorphic-fetch 重现此请求。
我试过以下代码:
const formData = new FormData();
formData.append('file', file);
formData.append('userId', userId);
return fetch(`<url>`, {
method: 'POST',
headers: {
'Content-Length': file.length
'Authorization: Bearer <authorization token>',
'Content-Type': 'multipart/form-data'
},
body: formData
})`
我使用 fs.readFileSync
来生成传递给 FormData
的 file
。
前面的示例 returns 一个 401
HTTP 状态代码(未授权)带有一条错误消息,指出 userId
嵌入到令牌中(通过 header 发送)与从 formData
.
userId
不匹配
所以我怀疑到达 REST API 的 FormData
没有充分形成。
问题可能与Content-Length
header有关,但我没有找到更好的计算方法(如果我不使用Content-Length
header 我得到一个 411
HTTP 状态代码 Content-Length
header 丢失)。
可能是因为 Content-Length
header 中的值不正确导致失败?
关于失败原因或如何更好地调试它的任何其他建议?
如果需要进一步的信息来澄清这个问题,请直接询问。
更新
我尝试了 form-data 模块,以便使用方法 formData.getLengthSync()
Content-Length
值
但是问题仍然存在(401
错误 HTTP 状态代码响应)。
如果您打开网络检查器,运行 此代码段,并提交表单,您应该会看到 Content-Length
设置正确:
const foo = document.getElementById('foo')
foo.addEventListener('submit', (e) => {
e.preventDefault()
const formData = new FormData(foo)
formData.append('userId', 123)
fetch('//example.com', {
method: 'POST',
body: formData
})
})
<form id="foo">
<input id="file" type="file" name="file"/><br><br>
<button type="submit">Submit</button>
</form>
我的头撞到了类似的墙上,特别是在节点上使用 isomorphic-fetch
到 POST 多部分表单。对我来说关键是找到 .getHeaders()
。请注意 NPM description for form-data
表明它会 "just work" 没有这个,但它似乎没有,至少在节点中没有(我认为浏览器注入 header 东西?)。
// image is a Buffer containing a PNG image
// auth is the authorization token
const form_data = new FormData();
form_data.append("image", png, {
filename: `image.png`,
contentType: 'application/octet-stream',
mimeType: 'application/octet-stream'
});
const headers = Object.assign({
'Accept': 'application/json',
'Authorization': auth,
}, form_data.getHeaders());
try {
const image_res = await fetch(url, {
method: 'POST',
headers: headers,
body: form_data
});
if (!image_res.ok) {
const out = await image_res.json();
console.dir(out);
return;
}
}
catch (e) {
console.error(`Chart image generation exception: ${e}`);
}