React Native Expo项目中的文件上传不起作用

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

我收到后端的响应“没有上传文件”。

import ImagePicker from "expo-image-picker";
export const UpdateProfile = () => {
  const [address, setAddress] = useState("");
  const [formPostImg, setFormPostImg] = useState("");

  const [errMsg, setErrMsg] = useState<Record<string, string>>({
    profile: "",
  });

  const openImageLibraryKeyMessage = async () => {
    const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (status !== "granted") {
      alert("Sorry, we need camera roll permissions to make this work!");
    }

    if (status === "granted") {
      const result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.All,
        allowsEditing: true,
      });

      if (!result.canceled) {
        setFormPostImg(result.assets[0].uri);
        console.log({ formPostImg });
      }
    }
  };

  const handleUpdateProfile = async () => {
    console.log("clicked");
    console.log({ formPostImg });

    const formBody = new FormData();
    formBody.append("address", address);
    formBody.append("img", formPostImg);
    try {
      const res = await updateProfileFn({
        formBody,
        setErrMsg,
      });
      if (res && res.message.includes("success")) {
        console.log("success");
      }
    } catch (error) {
      // disable empty object error
    }
  };

  return (
    <SafeAreaView style={styles.mainBox}>
      {errMsg.profile && <Text>{errMsg.profile}</Text>}
      <View>
        <Text>Address</Text>
        <TextInput
          onChangeText={setAddress}
          value={address}
          placeholder="Enter address"
          style={styles.textInput}
        />
      </View>

      <Pressable onPress={openImageLibraryKeyMessage}>
        <Text>Pick image</Text>
      </Pressable>

      <Pressable onPress={handleUpdateProfile}>
        <Text>Update</Text>
      </Pressable>
    </SafeAreaView>
  );
};

I console.log({ formPostImg });并得到类似于

的响应
LOG  {"formPostImg": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Ffrontend-a5b88748-c8d6-412d-b8cc-ee88decfab14/ImagePicker/72bb7e65-9d16-4a78-a14e-009cd8cca53c.jpeg"}

显示图像正在存储状态,但是当我尝试上传时,我从后端收到错误“未上传文件”

这是我调用的函数

async function updateProfileFn({
  formBody,
  setErrMsg,
}: {
  formBody: FormData;
  setErrMsg: React.Dispatch<React.SetStateAction<Record<string, string>>>;
}): Promise<ResSuccess | undefined> {
  const url = `${BASE_URL}/api/v1/users/updateProfile`;

  const token = await SecureStore.getItemAsync("token");
  console.log({ formBody });

  const res = await fetch(url, {
    method: "PATCH",
    headers: {
      "Content-Type": "multipart/form-data",
      Accept: "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: formBody,
  });

  if (!res.ok) {
    const exactErrorMsg = await res.json();
    const errorMsgString = JSON.stringify(exactErrorMsg);
    const errorMsg = JSON.parse(errorMsgString).error;

    // Set the error message in the state
    setErrMsg((prev) => ({ ...prev, profile: errorMsg }));

    // Throw an error to stop further execution
    return;
  }

  const data: ResSuccess = await res.json();

  console.log({ data });

  return data;
}
export default updateProfileFn;

这是更多上下文的后端代码

export const updateProfile: express.RequestHandler = (
  req: Request,
  res: Response
) => {
  const { id: user_id } = getUserIDAndToken(req);

  if (!user_id) {
    res.status(401).json({ error: "Unauthorized" });
    return;
  }

  upload.single("img")(req, res, async (err) => {
    if (err) {
      if (err.message === "Unexpected field") {
        // console.log(error.message);

        res.status(400).json({ error: "Maximum of 1 image allowed" });
        return;
      }
    }

    const {
      address,
      phone_number,
      account_name,
      email,
      tag,
    }: {
      address: string;
      phone_number: string;
      account_name: string;
      email: string;
      tag: string;
    } = req.body;
    console.log({ address, phone_number, account_name, email, tag });

    // create uniqueIdentifier for the image
    const uniqueIdentifier = Date.now() + "-" + Math.round(Math.random() * 1e9);

    // create publicId for the image for cloudinary
    const publicId = `profile-img-${uniqueIdentifier}`;

    console.log(req.files);
    console.log(req.file?.path);

    if (!req.file) {
      res.status(400).json({ error: "No file uploaded" });
      return;
    }

    if (!address || !phone_number || !account_name || !email) {
      res.status(400).json({ error: "Missing required fields" });
      return;
    }

    try {
      const result = await cloudinary.uploader.upload(req.file.path, {
        public_id: publicId,
      });
      const imgURL = result.secure_url;
      console.log("imgURL", imgURL);

      pool.execute<ResultSetHeader>(
        `
                UPDATE users
                SET img = ?, address = ?, phone_number = ?, account_name = ?, email = ?, tag = ?
                WHERE id = ?
                `,
        [imgURL, address, phone_number, account_name, email, tag, user_id],
        (err) => {
          if (err) {
            console.error(err);
            res.status(500).json({ error: "Internal server error" });
            return;
          } else {
            console.log({ result });
            res.status(200).json({ message: "Profile updated successfully" });
          }
        }
      );
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "Internal server error" });
    }
  });
};

这些的日志

console.log(req.files);
console.log(req.file?.path);

都是未定义的

react-native expo
1个回答
0
投票

我认为你的问题可能是你的formData。我这样做是为了使用 React Native 中的表单数据上传图像:

      formData.append(
        `${image.name}`,      <=== Name of upload
        {
          uri: image.uri,
          name: image.name,
          type: 'image/jpeg',
        },                    <== Blob
        `${image.name}`       <=== FileName
      );

这对我有用,所以希望这也是您的问题!

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