为什么我发送的表单数据中的图像文件大小为 0?

问题描述 投票:0回答:1

我可以使用 Postman 通过后端路由(到 Cloudinary)上传图像,但是每次我从前端(Expo/RN)发送图像时,我的后端都会出错,并显示 500 错误,指出文件为空(大小) : 0).

前端表单数据的控制台日志显示非零文件大小,因此我假设我的 Blob 和文件正在正确生成并附加到表单数据。在我的后端,我收到了正确数量的文件,但问题是它们的大小均为 0。

这是我的formData控制台日志:

formData [{"_data": {"__collector": [Object], "blobId": "a89556eb-d358-4fc5-846f-bb9a55292d3e", "lastModified": undefined, "name": "C6777AC5-64A4-4A03-8920-D7B2E2325345.jpg", "offset": 0, "size": 3566999, "type": "image/jpeg"}}, {"_data": {"__collector": [Object], "blobId": "6ca57385-48e8-450e-af7e-4dcd21844788", "lastModified": undefined, "name": "ABD5D206-8580-468C-9EDA-6C8D6F29F254.jpg", "offset": 0, "size": 4455509, "type": "image/jpeg"}}]

这是我的前端(世博会):

interface ImagePickerFormProps {
  page: number;
  setPage: React.Dispatch<React.SetStateAction<number>>;
  control: any;
}

export const ImagePickerForm = ({ control }: ImagePickerFormProps) => {
  const { setValue, watch } = useFormContext();
  const [status, requestPermission] = useMediaLibraryPermissions();

  const selectedAssets = watch("selectedAssets");

  const { mutateAsync } = useUploadPostMutation();

  const pickImages = async () => { // PICKED IMAGES ARE SAVED TO FORM CONTEXT
    const { status } = await requestMediaLibraryPermissionsAsync();

    if (status !== "granted") {
      await requestPermission();
    }

    const result = await launchImageLibraryAsync({
      mediaTypes: MediaTypeOptions.All,
      aspect: [16, 9],
      quality: 1,
      allowsMultipleSelection: true,
      orderedSelection: true,
      selectionLimit: 10,
      videoMaxDuration: 60,
      base64: true, // BASE64 NOT NEEDED?
    });

    if (!result.canceled) {
      setValue("selectedAssets", result.assets);
    }
  };

  const handleUploadToCloudinaryWithBlob2 = async () => {
    if (selectedAssets.length === 0) {
      console.log("selectedAssets has a length of 0");
      return;
    }

    const formData = new FormData();

    for (const asset of selectedAssets) {
      const fileNameParts = asset.uri.split(".");
      const fileExtension = fileNameParts[fileNameParts.length - 1];
      const fileName = asset.uri.split("/").pop()?.split(".")[0];
      const imageBlob = await fetch(asset.uri).then((response) =>
        response.blob()
      );
      console.log("imageBlob", imageBlob);
      console.log("imageBlob.type", imageBlob.type);
      console.log("imageBlob.size", imageBlob.size);

      const fileType = fileExtension === "jpg" ? "jpeg" : fileExtension; // HAD TO DO THIS BECAUSE BLOB TYPE CHANGED FROM JPEG TO JPG WHEN CREATING A NEW FILE... SEEMS STRANGE

      const blobFile = new File(
        [imageBlob],
        `${fileName}.${fileExtension}` || `image-${Date.now()}.${fileType}`,
        { type: `image/${fileType}` }
      );

      formData.append(`files`, blobFile, `${fileName}.${fileExtension}`);
    }

    console.log("formData", formData.getAll("files")); // SHOWS ARRAY OF IMAGES WITH NON-ZERO FILE SIZES

    try {
      const response = await axios.post(
        `${process.env.EXPO_PUBLIC_SERVER_URL}/posts/upload/cloudinary`,
        formData,
        {
          headers: {
            Accept: "application/json",
            "Content-Type": "multipart/form-data",
          },
          onUploadProgress: (progressEvent) => {
            if (progressEvent.total) {
              const progress = Math.round(
                (progressEvent.loaded * 100) / progressEvent.total
              );
              console.log(progress);
            }
          },
        }
      );

      console.log("Response:", response.data);
    } catch (error) {
      console.error("Error uploading images:", error);
    }
  };

  return (
    <Stack>
      <Stack flex={selectedAssets ? 0 : 1}>
        <Controller
          control={control}
          name="selectedAssets"
          rules={{ required: true }}
          render={() => (
            <Stack id="asset-form" flex={1} backgroundColor={"blue"}>
              <TouchableOpacity
                onPress={pickImages}
                style={{
                  justifyContent: "center",
                  alignItems: "center",
                  paddingVertical: 20,
                }}
              >
                <FontAwesome5 name="plus-circle" size={100} color="black" />
              </TouchableOpacity>
            </Stack>
          )}
        />
      </Stack>
      <Stack
        flexDirection="row"
        flexWrap="wrap"
        justifyContent="space-between"
        marginHorizontal={10}
        rowGap={20}
        flex={selectedAssets ? 0 : 1 / 2}
      >
        {renderImages()}
      </Stack>
      <Button onPress={handleUploadToCloudinaryWithBlob2}>
        Upload to cloudinary
      </Button>
    </Stack>
  );
};


我已经看了几十个问题和答案,但我仍然陷入困境。我尝试过将图像作为 base64、Blob 和文件发送,但每次我的后端都没有收到图像。

image post axios expo blob
1个回答
0
投票

确保您使用的是 Form-Data npm 包。我在 Expo/React Native 中使用内置的 FormData 模块,但它不起作用,因为表单类型是 string |斑点。

© www.soinside.com 2019 - 2024. All rights reserved.