React Native上传图片时出现网络请求失败

9
我正在尝试从React Native捕获并上传图像到服务器,但是当我进行HTTP请求时出现以下错误:[TypeError:网络请求失败]。这是我的代码,我已经按照这个教程进行了操作:

https://heartbeat.fritz.ai/how-to-upload-images-in-a-react-native-app-4cca03ded855

import React from 'react';
import {View, Image, Button} from 'react-native';
import ImagePicker from 'react-native-image-picker';

export default class App extends React.Component {
  state = {
    photo: null,
  };

  createFormData = (photo) => {
    const data = new FormData();

    data.append('photo', {
      name: photo.fileName,
      type: photo.type,
      uri:
        Platform.OS === 'android'
          ? photo.uri
          : photo.uri.replace('file://', ''),
    });

    data.append('id', 1);
    return data;
  };

  handleChoosePhoto = () => {
    const options = {
      noData: true,
    };
    ImagePicker.launchImageLibrary(options, (response) => {
      if (response.uri) {
        this.setState({photo: response});
      }
    });
  };

  handleUploadPhoto = () => {
    fetch('http://192.168.1.104:3000/', {
      method: 'POST',
      body: this.createFormData(this.state.photo),
    })
      .then((response) => response.text())
      .then((response) => {
        console.log('upload success', response);
      })
      .catch((error) => {
        console.log('upload error', error);
      });
  };

  render() {
    const {photo} = this.state;
    return (
      <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
        {photo && (
          <React.Fragment>
            <Image
              source={{uri: photo.uri}}
              style={{width: 300, height: 300}}
            />
            <Button title="Upload" onPress={this.handleUploadPhoto} />
          </React.Fragment>
        )}
        <Button title="Choose Photo" onPress={this.handleChoosePhoto} />
      </View>
    );
  }
}

我已经尝试过:

  • 在http请求头中添加“Content: multipart/form-data”
  • 在http请求头中添加“Accept: application/json”

我注意到,只有当我将照片对象添加到“FormData”中时,请求才会失败,也就是说,当我删除以下代码时,http请求才能正确运行:

data.append('photo', {
      name: photo.fileName,
      type: photo.type,
      uri:
        Platform.OS === 'android'
          ? photo.uri
          : photo.uri.replace('file://', ''),
    });

编辑 2020年02月07日

我终于在这里找到了解决方案:

https://github.com/facebook/react-native/issues/28551#issuecomment-610652110


我正在使用以下软件包:"react": "16.11.0", "react-native": "0.62.2", "react-native-image-picker": "^2.3.1"我正在开发的手机是小米红米Note 5。 - Juan Diego Cardona Marin
你尝试过将 'file://' + photo.path 添加为安卓的 uri 吗? - Chathurika Senani
因为“网络请求失败”错误而来到此处的人可能会有兴趣阅读此链接 - otaku
5个回答

5
第一个问题在于imageUri本身。比如说,如果照片路径为/user/.../path/to/file.jpg,则Android中的文件选择器将给出imageUri值为file:/user/.../path/to/file.jpg,而iOS中的文件选择器将给出imageUri值为file:///user/.../path/to/file.jpg。
第一个问题的解决方法是在Android的formData中使用file://而不是file:。
第二个问题是我们没有使用正确的MIME类型。在iOS上工作正常,但在Android上不行。更糟糕的是,文件选择器包将文件类型设置为“image”,而不是正确的MIME类型。
解决方法是在formData的字段类型中使用正确的MIME类型。例如:.jpg文件的MIME类型为image/jpeg,.png文件的MIME类型为image/png。我们不必手动执行此操作。相反,可以使用非常著名的npm包mime。
import mime from "mime";

const newImageUri =  "file:///" + imageUri.split("file:/").join("");

const formData = new FormData();
formData.append('image', {
 uri : newImageUri,
 type: mime.getType(newImageUri),
 name: newImageUri.split("/").pop()
}); 

1
要获取有关此解决方案的更多信息,请查看此处:https://forums.expo.dev/t/network-request-failed-while-uploading-image-to-server/30737/5 - Anthony phillips
1
您还需要通过运行expo install mime或npm install mime来安装mime。 - Anthony phillips

1

这个解决方案 同样适用:

我在我的React Native项目中遇到了同样的问题,使用版本0.62。 我将Flipper更新到“0.41.0”版本,问题得以解决。

在gradle.properities文件中

FLIPPER_VERSION=0.41.0

gradle.properties文件位于PROJECT_ROOT/android目录下。


1
const URL = "ANY_SERVER/upload/image"
  const xhr = new XMLHttpRequest();
  xhr.open('POST', url); // the address really doesnt matter the error occures before the network request is even made.
  const data = new FormData();
  data.append('image', { uri: image.path, name: 'image.jpg', type: 'image/jpeg' });

  xhr.send(data);
  xhr.onreadystatechange = e => {
    if (xhr.readyState !== 4) {
      return;
    }

    if (xhr.status === 200) {
      console.log('success', xhr.responseText);
    } else {
      console.log('error', xhr.responseText);
    }
  };

0
const launchCamera = () => {
  let options = {
    storageOptions: {
      skipBackup: true,
      path: "images",
    },
  };
  ImagePicker.launchCamera(options, (response) => {
    console.log("Response = ", response);
    if (response.didCancel) {
      console.log("User cancelled image picker");
    } else if (response.error) {
      console.log("ImagePicker Error: ", response.error);
    } else if (response.customButton) {
      console.log("User tapped custom button: ", response.customButton);
      alert(response.customButton);
    } else {
      const source = { uri: response.uri };
      console.log(
        "response in image pleae chec nd xcjn",
        JSON.stringify(response)
      );
      this.setState({
        filePath: response,
        fileData: response.data,
        fileUri: response.uri,
      });
    }
    imageUpload(response);
  });
};

const imageUpload = (imageUri) => {
  console.log('imageuril',imageUri);
  const newImageUri =  "file:///" + imageUri.assets[0].uri.split("file:/").join("");
  const imageData = new FormData()
  imageData.append("file", {
    uri: newImageUri,
    type: mime.getType(newImageUri),
    name: newImageUri.split("/").pop()
  })
  console.log("form data", imageData)
  axios({
    method: 'post',
    url: 'https://example.com/admin/api/v1/upload_reminder/1',
    data: imageData
  })
    .then(function (response) {
      console.log("image upload successfully", response.data)
    }).then((error) => {
      console.log("error riased", error)
    })

}

使用此代码,百分之百有效


从 "mime" 导入 mime;安装这个插件,100% 代码工作。 - GUGAN RAJ

0

我几天前遇到了类似的问题。 对我来说,问题是photo.type返回了错误的类型。所以我只是手动添加了它。

fd.append('documentImages', {
      name: getImgId(img.uri) + '.jpg',
      type: 'image/jpeg',
      uri: Constants.platform.android
        ? img.uri
        : img.uri.replace('file://', ''),
    })

这些是我打印图像某些属性时得到的值:文件名: IMG-20200617-WA0022.jpg
类型: image/jpeg
URI: content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FWhatsApp%2FMedia%2FWhatsApp%20Images%2FIMG-20200617-WA0022.jpg
- Juan Diego Cardona Marin
发布失败时是否有任何错误消息?不要仅仅在控制台中记录错误。检查错误对象,也许你会在那里找到有用的信息。 - pvtallulah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接