通过Axios发送Blob文件

pdkcd3nj  于 2023-10-18  发布在  iOS
关注(0)|答案(3)|浏览(1952)

我有这样的对象:

{
    "name": "filename",
    "size": 3523507,
    "type": "image/png",
    "extension": "png",
    "url": "blob:http://localhost:8081/082e9c22-9869-4289-a9c8-e36b0640e61c"
}

我需要上传到后台。我试试:

const session = axios.create({
  baseURL: debug ? 'http://localhost:8000': '',
  xsrfCookieName: CSRF_COOKIE_NAME,
  xsrfHeaderName: CSRF_HEADER_NAME,
});
let formData = new FormData();
formData.append('file', file, 'file.name');

return session.post(`/chats/files/`,{...formData},), {
  headers: {
    "Content-Type": `multipart/form-data`,
  }
}

但是将Blob添加到formData中并不起作用
UPD我从vue-advanced-chat组件中的send-message方法中获取一个带有文件的对象,格式如下:

{
    "name": "filename",
    "size": 3523507,
    "type": "image/png",
    "extension": "png",
    "localUrl": "blob:http://localhost:8081/aae047a9-5f9e-481f-b0cc-17febe954c31",
    "blob": {}
}

然后在上传到服务器之前将其格式化以显示在界面中
UPD2
我将blob转换为文件

send_file(roomId, messageId, blob_file, isAudio, duration) {
        let formData = new FormData();
        let file = new File([blob_file.blob], blob_file.name);
        formData.append('file[]', file, blob_file.name);
        return session.post(`/chats/files/`,
            {'chat': roomId, 'message': messageId, ...formData},), {
            headers: {
              'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
            },
            timeout: 30000,
        }
    },

仍然可以得到:{“file”:[“未发送文件。"]}

lymgl2op

lymgl2op1#

经过几天的搜索、调试和几十次尝试,我终于找到了解决方案。
1.您需要一个Blob对象,而不是URL
1.您需要将%{v_扩展}转换为文件let file = new File([blob_file.blob], fileName);
1.要正确识别文件类型,需要将blob_file.extension添加到名称let fileName =${blob_file.name}.${blob_file.extension};
1.您需要将所有属性添加到formData

formData.append('file', file, fileName);
formData.append('chat', roomId);
formData.append('message', messageId);

1.指定“内容类型”:multipart/form-data,并且不要指定_boundary -因为在新版本的formData中,它是自动确定的!

headers: {
   'Content-Type': `multipart/form-data`,
},

所以代码的最终版本看起来像这样:

send_file(roomId, messageId, blob_file) {
    let formData = new FormData();
    let fileName = `${blob_file.name}.${blob_file.extension}`;
    let file = new File([blob_file.blob], fileName);
    formData.append('file', file, fileName);
    formData.append('chat', roomId);
    formData.append('message', messageId);

    return session.post(`/chats/files/`,
        formData, {
           headers: {
             'Content-Type': `multipart/form-data`,
           },
        })
trnvg8h3

trnvg8h32#

您没有以正确的方式发送数据。它应该是:

export const uploadFileRequest = ({ file }) => {
   const data = new FormData();
   data.append('file', file, file.name);

   return session.post(`/chats/files/`, data, {
     headers: {
       'Content-Type': `multipart/form-data;boundary=${data._boundary}`,
     },
     timeout: 30000,
   });
};

它应该工作,参考https://medium.com/@fakiolinho/handle-blobs-requests-with-axios-the-right-way-bb905bdb1c04

5f0d552i

5f0d552i3#

我来到这个问题,几个小时后,这里是我的发现和解决方案。首先,我意识到像blob这样的二进制数据不能通过json发送。Axios通常以JSON格式发送数据,因此后端不会收到任何数据。这里需要设置header:

const data = new FormData();
      data.append("username", "Chris");
      data.append("file", userAnswers[0].value);

      let apiEndPoint = "/api/plans/answer/speaking/" + planId;
      axiosInstance
        .post(apiEndPoint, data, {
          headers: {
            "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
          },
          timeout: 30000,
        })
        .then(() => {
          toast({
            title: `Submitted`,
            status: "success",
            isClosable: true,
          });
          navigate("/");
        })

我们也看到了FormData的使用。这是必要的。也许你创建了一个表单,并在那里提到了类型。我没有用表格。

<form action="/stats" enctype="multipart/form-data" method="post">

第二个重要的部分是处理后端。前端部分是不够的。需要Multer中间件。

const multer = require("multer");
const upload = multer({ dest: "./public/data/uploads/" });

router.post(
  "/answer/speaking/:id",
  [auth, validateObjectId, upload.single("file")],
  async (req, res) => {
    winston.info(req.file);
    winston.info(req.body);
    res.send();
    return;
})

相关问题