Axios POST 请求不使用“multipart/form-data”发送任何内容 [React Native - Expo]

2024-04-05

Scenario

前端基本上是一个 React Native (Expo) 应用程序,用户可以在其中发布报告 - 这包括拍摄多张照片并填写一些详细信息。

后端只是node.js,带有 Express 和 Multer。

Problem

我使用 Axios 通过以下方式发送图像和表单数据FormData(),但是在服务器端,req.body 和 req.files 不包含任何内容.

这里的一件事是,通过 POSTMAN 发送相同的数据工作完全正常,图像存储到 S3 中,表单详细信息存储在数据库中。这是通过应用程序/模拟器不起作用。

我尝试删除“multipart/form-data”标头,这是 console.log(req.body) 的输出(req.files 显示未定义):

{
  _parts: [
    [ 'userId', '1f400069-07d0-4277-a875-cbb2807750c5' ],
    [
      'location',
      'some location'
    ],
    [ 'description', 'Aaaaa' ],
    [ 'report-images', [Object] ]
  ]
}

当我把“multipart/form-data”标题放回去时,这个输出甚至没有出现。

我做了什么

过去几个小时我一直在寻找解决方案,但没有一个有效。这些解决方案是:

  1. 在“multipart/form-data”标题后面添加边界
  2. 将类型设置为“image/jpeg”
  3. 将文件 uri 修剪为“file://”

但它们都不起作用

这是我的代码:

React Native 前端(博览会)

   const submitReport = async () => {
    setShowLoading(true);

    // Validate details (location & images)
    if (location === "") {
        setShowLoading(false);
        showToast(7002);
        return;
    }

    if (images.length === 0) {
        setShowLoading(false);
        showToast(7004);
        return;
    }

    try {
        const formData = new FormData();
        formData.append("userId", user.userId);
        formData.append("location", location);
        formData.append("description", description);
        images.forEach(img => {
            const trimmedURI = (Platform.OS === "android") ? img.uri : img.uri.replace("file://", "");
            const fileName = trimmedURI.split("/").pop();
            const media = {
                name: fileName,
                height: img.height,
                width: img.width,
                type: mime.getType(trimmedURI),
                uri: trimmedURI
            };

            formData.append("report-images", media);
        });

        const response = await axios.post(`http://<my-ip-address>:3003/api/report/submit`, formData, { headers: { 'Content-Type': "application/x-www-form-urlencoded" } });
        console.log(response)
        setShowLoading(false);
    }
    catch (error) {
        console.log(error);
        setShowLoading(false);
        showToast(9999);
    }
};

Backend

// Multer-S3 Configuration
const upload = multer({
    storage: multerS3({
        s3: s3,
        bucket: process.env.AWS_S3_BUCKET_NAME,
        contentType: (req, file, callback) => {
            callback(null, file.mimetype);
        },
        metadata: (req, file, callback) => {
            callback(null, { fieldName: file.fieldname });
        },
        key: (req, file, callback) => {
            callback(null, `${process.env.AWS_S3_REPORT_IMAGES_OBJECT_PATH}${req.body.userId}/${new Date().getTime().toString()}-${file.originalname}`)
        }
    }),
    fileFilter: (req, file, callback) => {
        // Check if file formats are valid
        if (file.mimetype === "image/png" || file.mimetype === "image/jpg" || file.mimetype === "image/jpeg") {
            callback(null, true);
        }
        else {
            callback(null, false);
            return callback(new Error("Image File Type Unsupported"));
        }
    },
});

router.post("/submit", upload.array("report-images", 3), async (req, res) => {
    try {
        // req -> FormData consisting of userId, location & description
        // multer-s3 library will handle the uploading to S3 - no need to code here
        // Details of files uploaded on S3 (Bucket, Key, etc.) will be displayed in req.files
        
        // Analyze from Rekognition
        //Add to Database code blablabla

        if (result.success === true) {
            res.status(200).send({ message: result.data });
        }
        else if (result.success === false) {
            res.status(404).send({ error: ERROR_MESSAGE });
        }
    }
    catch (error) {
        console.log(error);
        res.status(404).send({ error: ERROR_MESSAGE });
    }
});

我不确定这是 Axios 的问题还是我这边的问题。

这个项目是我的最后一年项目。


在深入研究 Google 的搜索结果后,我发现了 StackOverflow 的这篇文章:使用 axios 将本机表单数据与其中的对象和文件反应 https://stackoverflow.com/questions/56235286/react-native-post-form-data-with-object-and-file-in-it-using-axios

我在代码中获取了 user_2738046 提供的答案,它成功了!结合阿里的建议,这是最终有效的代码。

const FormData = global.FormData;
const formData = new FormData();
formData.append("userId", user.userId);
formData.append("location", location);
formData.append("description", description);
images.forEach(img => {
    const trimmedURI = (Platform.OS === "android") ? img.uri : img.uri.replace("file://", "");
    const fileName = trimmedURI.split("/").pop();
    const media = {
        name: fileName,
        height: img.height,
        width: img.width,
        type: mime.getType(trimmedURI),
        uri: trimmedURI
    };

    formData.append("report-images", media);
});
            
const response = await axios({
    method: "POST",
    url: `http://${<my-ip-address>}:3003/api/report/submit`,
    data: formData,
    headers: {
        'Content-Type': 'multipart/form-data'
    },
    transformRequest: (data, error) => {
        return formData;
    }
});

// If success, clear all text fields
if (response) {
    showToast(7005);
    setLocation("");
    setImages([]);
    setDescription("");
}

setShowLoading(false);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Axios POST 请求不使用“multipart/form-data”发送任何内容 [React Native - Expo] 的相关文章

随机推荐