React Native blob/文件未到达服务器

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

我被困在这里了。我不知道我做错了什么。我正在尝试将文件从 expo-image-picker 组件 发送到服务器。表格已发送,但图像未发送。

fetch
命令立即给出“网络请求失败”错误。服务器确实收到了请求,但没有附加图像。

更多信息:

  • 我正在创建表单数据对象并将 blob 附加到其中。我也尝试过用

    FormData.append("image", {uri, name: 'filename', type: 'image/filetype'})
    来做这件事,大多数文章建议的方式,忽略 TS 错误,但它也失败了。

  • 我没有提交给AWS或Firebase,所以我没有使用这些库,无论如何我看不出他们在做什么与我有什么不同。

  • 我没有为此设置任何特定权限。我确实看到一些文章谈论上传权限,但它们已经超过 5 年了,并且谈论的是 android 5.0 之前的内容。

这是我用来提交的函数。

pathToImage
从 ImagePicker 返回。

const fetchImageFromUri = async (uri: string) => {
  try {
    const response = await fetch(uri);
    const blob = await response.blob();

    return blob;
  } catch (error) {
    console.log("fetchImageFromUri error:", error);
    throw new Error("fetchImageFromUri");
  }
};

const upload = async () => {
  setMessage("");
  setErrMessage("");

  if (pathToImage != null) {
    const fileToUpload = await fetchImageFromUri(pathToImage);

    const formData = new FormData();
    formData.append("action", "Image Upload");
    formData.append("image", fileToUpload, "filename");

    // from: https://stackoverflow.com/questions/71198201/react-native-unable-to-upload-file-to-server-network-request-failed
    // most articles say this is the way to upload the file... Typescript gives an error
    // because it only wants type 'string | Blob'
    // let uriParts = pathToImage.split(".");
    // let fileType = uriParts[uriParts.length - 1];
    // formData.append("image", {
    //   uri: pathToImage,
    //   name: `photo.${fileType}`,
    //   type: `image/${fileType}`,
    // });

    // create the header options
    const options: RequestInit = {
      method: "POST",
      body: formData,
      headers: {
        "Content-Type": "multipart/form-data",
        Accept: "image/jpeg, image/png",
      },
    };

    try {
      const res = await fetch(URL, options);
            
      console.log("fetch returned"); // this line is never reached
            
      if (!res.ok) {
        throw new Error("Something went wrong");
      }

      const body = (await res.json()) as any;
            
      if (body.code > 200) {
        setErrMessage(body.msg);
      } else {
        setMessage(body.msg);
      }
    } catch (err: any) {
      setErrMessage("There was an error in upload");
      console.log("upload catch error:", err.message);
    }
  }
};

完整代码可以在我的 GitHub 存储库中找到。

typescript react-native expo fetch-api
2个回答
0
投票

感谢 Brandonjgs 为我指明了正确的方向。我能够解决这个问题。

这是新的上传功能。

const upload = async () => {
    console.log("\n***** Upload Image *****");
    setMessage("");
    setErrMessage("");
    setLoading(true);

    if (pathToImage) {
        console.log("***** get other fields section *****");
        const dataToSend: Record<string, string> = {};
        dataToSend["action"] = "Image Upload";

        console.log("***** Options section *****");
        const options: FileSystemUploadOptions = {
            headers: {
                "Content-Type": "multipart/form-data",
                Accept: "image/jpeg, image/png",
            },
            httpMethod: "POST",
            uploadType: FileSystemUploadType.MULTIPART,
            fieldName: "image",
            parameters: dataToSend,
        };

        console.log("***** 'Fetch' section *****");
        try {
            const response = await FileSystem.uploadAsync(
                URL,
                pathToImage,
                options
            );

            setLoading(false);

            if (response.status >= 200 && response.status < 300) {
                const body = JSON.parse(response.body);
                setMessage(body.msg);
            } else {
                setErrMessage(`${response.status} Error: ${response.body}`);
            }
        } catch (err: any) {
            console.error(err);
            setErrMessage(err.message);
        }
    }
};

请务必查看 FileSystem.uploadAsync 文档。它不返回标准的 http 响应,它会格式化自己的响应并仅返回:

  • status
    :错误代码
  • header
    :服务器返回的http header
  • body
    :无论服务器“发送”回来什么——在我的例子中它是 JSON。请注意,如果服务器没有响应或者它是一个错误的 URL,它会返回一个 HTML 错误页面,而不是一个标准错误消息字符串(我发现这是一个奇怪的选择,因为这是本地反应,我不一定导航到新的当我上传页面时,我捕获状态对象中的字符串以发布响应)。

0
投票

我也有同样的错误。这是我的代码,我总是得到 403 fordden

export const pickImage = async () => {
  const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
  if (status !== "granted") {
    alert("Permission to access media library is required!");
    return;
  }

  const result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.All,
    allowsEditing: true,
    aspect: [4, 3],
    quality: 1,
    base64:true
  });

  if (!result.canceled) {

    const uri = result.assets[0].uri;
    const fileName = uri.split('/').pop();
    const fileType = mime.getType(uri) || "image/jpeg";

    if (Platform.OS === 'web') {
      // Conversion en Blob pour le web */
      const response = await fetch(uri);
      const blob = await response.blob();

      file = new File([blob], fileName, { type: fileType });
     } else {
     
  /*     {
        uri:
          Platform.OS === "android"
            ? pickedImage.uri
            : pickedImage.uri.replace("file://", ""),
        name: "tata.jpeg",
        type: "image/jpeg",
      } */
      // Utilisation de l'URI directement pour le mobile
      file = {
        uri:  Platform.OS === "android" ? uri
        : uri.replace("file://", ""),
        name: fileName,
        type: fileType,
      }; 
      console.log(file);
/*       console.log("voire ",file.name) */
    } 

        return {
      response: file,
      error: null,
    }; 
  }

  return null;
};
© www.soinside.com 2019 - 2024. All rights reserved.