如何使用fetch和FormData发送二进制数据(blob)?

Dav*_*lla 9 javascript fetch

以下代码按预期工作.在Google Chrome上打开" https://wiki.epfl.ch/ " 页面,然后在Developer Console上执行此代码.注意:页面" https://wiki.epfl.ch/test.php "不存在,因此无法加载,但这不是问题.

response = await fetch(""https://wiki.epfl.ch/lapa-studio/documents/DTS/laser%20tutorial.pdf"");
response.text().then(function(content) { 
  formData = new FormData();
  console.log(content.length);
  console.log(content);
  formData.append("content", content);

  fetch("https://wiki.epfl.ch/test.php", {method: 'POST', body: formData});
})
Run Code Online (Sandbox Code Playgroud)

它记录:

content.length: 57234
content: %PDF-1.3
%?????????
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
x??K??F?????;¢?
...
Run Code Online (Sandbox Code Playgroud)

转到Developer Network选项卡,选择'test.php'页面,导航到"Requested payload:",您可以看到以下内容:

------WebKitFormBoundaryOJOOGb7N43BxCRlv
Content-Disposition: form-data; name="content"

%PDF-1.3
%?????????
4 0 obj
<< /Length 5 0 R /Filter /FlateDecode >>
stream
...
------WebKitFormBoundaryOJOOGb7N43BxCRlv
Run Code Online (Sandbox Code Playgroud)

问题是请求文件是二进制文件(PDF),文本被"损坏".当实际文件大小(使用wget命令获取)为60248字节时,它报告大小为57234字节.

问题是:如何获取和发送二进制数据,而不进行修改?


我试着更换response.text()response.blob(),如下:

response = await fetch("https://wiki.epfl.ch/lapa-studio/documents/DTS/laser%20tutorial.pdf");
response.blob().then(function(content) { 
  console.log(content.size);
  console.log(content);
  formData = new FormData();
  formData.append("content", content);

  fetch("https://wiki.epfl.ch/test.php", {method: 'POST', body: formData});
})
Run Code Online (Sandbox Code Playgroud)

现在我得到这个日志,文件大小正确:

content.size:  60248
content:  Blob(60248) {size: 60248, type: "application/pdf"}
Run Code Online (Sandbox Code Playgroud)

但是,进入Developer Network选项卡,选择'test.php'页面,导航到"Requested payload:",它显示它发送一个空的有效负载:

------WebKitFormBoundaryYoibuD14Ah2cNGAd
Content-Disposition: form-data; name="content"; filename="blob"
Content-Type: application/pdf


------WebKitFormBoundaryYoibuD14Ah2cNGAd--
Run Code Online (Sandbox Code Playgroud)

注意:我正在开发的网页不在wiki.epfl.ch. 我提供此示例以便用户可以尝试(并避免"跨源资源共享"问题).我的"test.php"页面在php中并$_POST['content']在使用时返回内容response.text(),但在使用时返回空response.blob().因此,即使开发人员网络选项卡"请求的有效负载:"不显示二进制数据,此剪切仍然无法正常工作.


问题是:如何获取和发送二进制数据,而不进行修改?

Pat*_*rts 10

如果要发送二进制文件,请不要使用该.text()方法,因为它会返回使用 UTF-8 解码的文件,这不是您想要的。相反,使用.blob()不尝试解码文件的方法,并将其直接用作body第二个的参数,fetch()因为它允许是 a Blob

const response = await fetch("https://wiki.epfl.ch/lapa-studio/documents/DTS/laser%20tutorial.pdf");
const content = await response.blob();
console.log(content.size);
fetch("https://wiki.epfl.ch/test.php", { method: 'POST', body: content });
Run Code Online (Sandbox Code Playgroud)

要解析此上传格式,请参阅此答案

如果您想将其作为multipart/form-data格式化附件的一部分上传,您仍然可以使用FormDataAPI,但这样做并不是将二进制数据发送到您的 PHP 脚本所必需的。只是为了完整起见,您可以这样做:

const response = await fetch("https://wiki.epfl.ch/lapa-studio/documents/DTS/laser%20tutorial.pdf");
const content = await response.blob();
console.log(content.size);
const formData = new FormData();
formData.append("content", content);
fetch("https://wiki.epfl.ch/test.php", { method: 'POST', body: formData });
Run Code Online (Sandbox Code Playgroud)


小智 6

试试这个,通过将 blob 转换为 DataURL 字符串,您可以在不修改的情况下发送二进制数据。

response = await fetch("https://wiki.epfl.ch/lapa-studio/documents/DTS/laser%20tutorial.pdf");
response.blob().then(function (content) {

    let reader = new FileReader();

    reader.addEventListener("loadend", function () {

      formData = new FormData();
      formData.append("content", reader.result);
      fetch("https://wiki.epfl.ch/test.php", { method: 'POST', body: formData });
      reader.removeEventListener("loadend");

    });

    reader.readAsDataURL(content);

 });
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考,在这里使用 `FileReader` API 来缓冲 `Blob` 是完全没有必要的。[`formData.append()`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/append) 直接接受 `content` 作为 `value` 而不是将它缓冲到 `阅读器结果`。 (4认同)