node.js 如何使用 fetch 使用 multipart/form-data 标头和 FormData POST

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43500514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 18:10:34  来源:igfitidea点击:

How to POST with multipart/form-data header and FormData using fetch

node.jscurlfetch-apihttp-content-lengthisomorphic-fetch-api

提问by rfc1484

This is a CURL example which works fine:

这是一个运行良好的 CURL 示例:

curl -X POST \
  <url> \
  -H 'authorization: Bearer <token>' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F [email protected] \
  -F userId=<userId>

I'm trying to reproduce this request using isomorphic-fetch.

我正在尝试使用isomorphic-fetch重现此请求。

I've tried the following code:

我试过以下代码:

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
})`

I use fs.readFileSyncin order to generate the filepassed to FormData.

我使用fs.readFileSync以生成file传递给FormData.

The previous example returns a 401HTTP status code (unauthorized) with an error message saying that the userIdembedded in the token (sent via header) does not match the userIdpassed from formData.

前面的示例返回一个401HTTP 状态代码(未经授权),并带有一条错误消息,指出userId嵌入在令牌中(通过标头发送)与userIdformData.

So my suspicion is that the FormDatathat arrives to the REST API is not adequately formed.

所以我怀疑FormData到达 REST API 的 没有充分形成。

The problem may be related with the Content-Lengthheader, but I didn't find a better way to calculate it (if I don't use the Content-Lengthheader I get a 411HTTP status code Content-Lengthheader missing).

问题可能与Content-Length标头有关,但我没有找到更好的计算方法(如果我不使用Content-Length标头,则会丢失411HTTP 状态代码Content-Length标头)。

Could be the case that this is failing because of an incorrect value in the Content-Lengthheader?

可能是因为Content-Length标题中的值不正确而导致失败吗?

Any other suggestions on why this is failing or how to better debug it?

关于为什么会失败或如何更好地调试它的任何其他建议?

If further info is needed to clarify this problem, please just ask.

如果需要更多信息来澄清这个问题,请询问。

UPDATE

更新

I've tried the form-datamodule in order to get the right Content-Lengthvalue using the method formData.getLengthSync()

我已经尝试了form-data模块,以便Content-Length使用该方法获得正确的值formData.getLengthSync()

However the problem remains the same (401error HTTP status code response).

但是问题仍然存在(401错误 HTTP 状态代码响应)。

采纳答案by idbehold

If you open up your network inspector, run this code snippet, and submit the form you should see that the Content-Lengthis set correctly:

如果您打开网络检查器,运行此代码片段,然后提交表单,您应该会看到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>

回答by Iain Bryson

I hit my head against a similar wall, specifically using isomorphic-fetchon node to POST a multipart form. The key for me was finding .getHeaders(). Note that NPM description for form-datasuggests that it'll "just work" without this, but it doesn't seem to, at least not in node (I think browsers inject header stuff?).

我的头撞到了类似的墙上,特别是isomorphic-fetch在节点上使用 POST 多部分表单。对我来说,关键是找到.getHeaders(). 请注意,NPM 的描述form-data表明它会在没有这个的情况下“正常工作”,但它似乎没有,至少在节点中没有(我认为浏览器会注入标头内容?)。

// 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}`);
}