【问题标题】:Problem sending file in POST request to API using Axios from a Firebase Function使用 Firebase 函数中的 Axios 将 POST 请求中的文件发送到 API 时出现问题
【发布时间】:2021-06-16 09:21:11
【问题描述】:

我正在使用表单数据和 Axios 将文件从 Firebase 函数上传到另一个 API。但是,当我将createReadStream(filePath) 添加到我的formData 对象并将其附加到我的POST 请求时,响应会给出400 状态代码,声称该文件不存在。我的代码:

const { fileName } = data;
const tempFilePath = path.join(os.tmpdir(), 'image.jpg');
const bucket = admin.storage().bucket();

await bucket.file(fileName).download({destination: tempFilePath});
   
let formData = new FormData();
formData.append('photo', fs.createReadStream(tempFilePath));

const formHeaders = formData.getHeaders();

await axios.post('api/endpoint', formData, {
    headers: {
      ...formHeaders
    }
  }).catch(err => {
    console.error(err.response.data)
  });

我在Post请求后得到的错误状态码为400,如下:

{ error: 'invalid_query_missing_photo', ok: false }

我已验证tempFilePath 确实会生成一个实际文件,并且我能够从 Postman 发出请求。但是,即使是从 Postman 的代码生成功能生成的代码也会导致同样的错误。

我的导入语句:

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
const axios = require('axios');

// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
const path = require('path');
const os = require('os');
const fs = require('fs');
const { firebaseConfig } = require('firebase-functions');
const FormData = require('form-data');

【问题讨论】:

    标签: javascript node.js axios


    【解决方案1】:

    错误 400 来自第二个 API,可能需要其他内容才能将获取请求标记为有效,或者所需字段未命名为 photo

    我测试了您的代码并创建了另一个模拟第二个 API 的函数,在我的第二个 API 中,当表单的文件字段与 API 中的要求不匹配时,我遇到了 HTTP 错误400

    第二个API代码(python写的函数)

    import os
    
    def hello_world(request):
            print(request.files)
    
            #this must match with the form field or you gonna receive an error 400
            file = request.files['photo'] 
            filename="cool.png"
            file.save(os.path.join("/tmp", filename))
    
            #this is to verify that the object were saved and is in /tmp
            print('Size         :', os.path.getsize(os.path.join("/tmp", filename)))
    
            return f'Hello World!'
    

    通过第二个函数,我可以验证问题不是来自您的函数代码。

    【讨论】:

    • 我知道错误来自我正在调用的 API,但我知道错误是声称照片丢失。它给出了一个状态码 400 以及这个特定的错误:{ error: 'invalid_query_missing_photo', ok: false } 我可以通过 Postman 调用 API,参数不超过我在代码中使用的参数,但即使是 Postman 生成的代码对于 Axios 环境以相同的错误结束。它必须是照片的上传方式。我将三次检查我是否使用了正确的参数,但由于它是由 Postman 工作的(但不是使用 JS 代码),我很困惑。
    • 也许是因为我以某种方式从 Firebase 函数运行它?这似乎是唯一的变化,并且可以解释为什么 NodeJS/Axios Postman 生成的代码不起作用,但我不确定为什么从使用 Node 环境的 Firebase 函数运行它会导致这种操作不起作用.
    • @BryceChampaign 没有来自另一个 API 的更多信息是不可能提供更多帮助的,这看起来不是云造成的问题。您的节点应用程序在本地 node.js 服务器上运行良好吗?
    【解决方案2】:

    我发现您需要使用 createReadStream 中的 getRawBody,但仅限于云函数。这是最终对我有用的 google cloud firebase 功能:

    const fullFile = await getRawBody(fs.createReadStream(fileLocation));
    
        ...
    
    formData.append('file', fullFile, { filename: 'somename.png'} );
    
        ...
    
    await axios.post('api/endpoint', formData.getBuffer(), {
      headers: {
        ...formHeaders
      }
    }).catch(err => {
        console.error(err.response.data)
    });
    

    这解决了我的错误:

     TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type object
    

    本地 readstream 似乎会自动转换成一个完整的缓冲区,但在云服务器上则需要手动转换。似乎在任何地方都没有关于此的任何文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-21
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 2019-08-08
      • 1970-01-01
      相关资源
      最近更新 更多