【问题标题】:How to use FormData in react-native?如何在 react-native 中使用 FormData?
【发布时间】:2015-12-03 04:53:39
【问题描述】:

你好,学习使用 js 和 react-native。我不能使用 FormData 它总是显示不支持的 bodyinit 类型。我想发送文本而不是 JSON.stringify。谁能帮我?谢谢!

var data = new FormData()
data.append('haha', 'input')

fetch('http://www.mywebsite.com/search.php', { 
  method: 'post',
  body: data
})
.then((response) => response.json())
.then((responseData) => {
  console.log('Fetch Success==================');
  console.log(responseData);

  var tempMarker = [];
  for (var p in responseData) {
   tempMarker.push({
    latitude: responseData[p]['lat'],
    longitude: responseData[p]['lng'] 
   })
  }

  this.setState({
    marker: tempMarker
  });

})
.catch((error) => {
  console.warn(error);
})
.done();

【问题讨论】:

  • 实际的错误信息是什么?
  • "不支持的 bodyinit 类型"
  • 在 react-native make sure not to have the react-native debugger attached 中处理 FormData 时。否则你会有问题。

标签: javascript react-native fetch-api


【解决方案1】:

这对我有用

var serializeJSON = function(data) {
  return Object.keys(data).map(function (keyName) {
    return encodeURIComponent(keyName) + '=' + encodeURIComponent(data[keyName])
  }).join('&');
}

var response = fetch(url, {
  method: 'POST',
  body: serializeJSON({
    haha: 'input'
  })
});

【讨论】:

  • 我怎样才能只使用文本?不是json
  • var response = fetch(url, { method: 'POST', body:encodeURIComponent("haha") + '=' + encodeURIComponent("input") });
【解决方案2】:

这是我的简单代码 FormData 与 react-native 来发布带有字符串和图像的请求。

我使用 react-native-image-picker 来捕捉/选择照片 react-native-image-picker

let photo = { uri: source.uri}
let formdata = new FormData();

formdata.append("product[name]", 'test')
formdata.append("product[price]", 10)
formdata.append("product[category_ids][]", 2)
formdata.append("product[description]", '12dsadadsa')
formdata.append("product[images_attributes[0][file]]", {uri: photo.uri, name: 'image.jpg', type: 'image/jpeg'})

注意您可以将image/jpeg 更改为其他内容类型。您可以从图像选择器响应中获取内容类型。

fetch('http://192.168.1.101:3000/products',{
  method: 'post',
  headers: {
    'Content-Type': 'multipart/form-data',
  },
  body: formdata
  }).then(response => {
    console.log("image uploaded")
  }).catch(err => {
    console.log(err)
  })  
});

【讨论】:

  • 我可以知道FormData 类是从哪里来的吗?我检查了 react-native-image-picker,它不在里面
  • 根据 MSDN 文档,FormData 应该有一个 set() 方法(例如在 Chrome 中),但显然这在 React Native 中不可用,所以解决方案确实是使用append()
  • 如果您对上述内容有疑问,请尝试在内容类型'Content-Type': 'multipart/form-data; boundary=someArbitraryUniqueString中添加“边界”
  • @bun:我按照你上面的例子,但是服务器端的 req.body 总是空的,请帮助
【解决方案3】:

我已将表单数据与ImagePicker 插件一起使用。 我让它工作了,请检查下面的代码

ImagePicker.showImagePicker(options, (response) => {
  console.log('Response = ', response);
  if (response.didCancel) {
    console.log('User cancelled photo picker');
  }
  else if (response.error) {
    console.log('ImagePicker Error: ', response.error);
  }
  else if (response.customButton) {
    console.log('User tapped custom button: ', response.customButton);
  }
  else {
    fetch(globalConfigs.api_url+"/gallery_upload_mobile",{
      method: 'post',
      headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
      ,
    body: JSON.stringify({
      data: response.data.toString(),
      fileName: response.fileName
    })
      }).then(response => {
        console.log("image uploaded")
      }).catch(err => {
        console.log(err)
      })  
  }
});

【讨论】:

  • 如何通过 JSON 发送多部分内容(检查您的 Content-Type 标头)
  • @AzeemHassni 根据您的评论更新我的答案,因为我在 base64 字符串中获取图像,这就是使用 json 的原因
【解决方案4】:

提供一些其他的解决方案;我们也在使用react-native-image-picker;并且服务器端使用koa-multer;这个设置运行良好:

用户界面

ImagePicker.showImagePicker(options, (response) => {
      if (response.didCancel) {}
      else if (response.error) {}
      else if (response.customButton) {}
      else {
        this.props.addPhoto({ // leads to handleAddPhoto()
          fileName: response.fileName,
          path: response.path,
          type: response.type,
          uri: response.uri,
          width: response.width,
          height: response.height,
        });
      }
    });

handleAddPhoto = (photo) => { // photo is the above object
    uploadImage({ // these 3 properties are required
      uri: photo.uri,
      type: photo.type,
      name: photo.fileName,
    }).then((data) => {
      // ...
    });
  }

客户

export function uploadImage(file) { // so uri, type, name are required properties
  const formData = new FormData();
  formData.append('image', file);

  return fetch(`${imagePathPrefix}/upload`, { // give something like https://xx.yy.zz/upload/whatever
    method: 'POST',
    body: formData,
  }
  ).then(
    response => response.json()
  ).then(data => ({
    uri: data.uri,
    filename: data.filename,
  })
  ).catch(
    error => console.log('uploadImage error:', error)
  );
}

服务器

import multer from 'koa-multer';
import RouterBase from '../core/router-base';

const upload = multer({ dest: 'runtime/upload/' });

export default class FileUploadRouter extends RouterBase {
  setupRoutes({ router }) {
    router.post('/upload', upload.single('image'), async (ctx, next) => {
      const file = ctx.req.file;
      if (file != null) {
        ctx.body = {
          uri: file.filename,
          filename: file.originalname,
        };
      } else {
        ctx.body = {
          uri: '',
          filename: '',
        };
      }
    });
  }
}

【讨论】:

  • 使用这个我得到:Expected URL scheme 'http' or 'https' but was 'file'
【解决方案5】:

react-native中formdata的使用

我使用react-native-image-picker 选择照片。在我的情况下,从移动设备中选择了 photp。我将它的信息存储在组件state 中。之后,我使用fetch 发送POST 请求,如下所示

const profile_pic = {
  name: this.state.formData.profile_pic.fileName,
  type: this.state.formData.profile_pic.type,
  path: this.state.formData.profile_pic.path,
  uri: this.state.formData.profile_pic.uri,
}
const formData = new FormData()
formData.append('first_name', this.state.formData.first_name);
formData.append('last_name', this.state.formData.last_name);
formData.append('profile_pic', profile_pic);
const Token = 'secret'

fetch('http://10.0.2.2:8000/api/profile/', {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "multipart/form-data",
      Authorization: `Token ${Token}`
    },
    body: formData
  })
  .then(response => console.log(response.json()))

【讨论】:

    【解决方案6】:

    如果要为 formData 项设置自定义内容类型:

    var img = {
        uri : 'file://opa.jpeg',
        name: 'opa.jpeg',
        type: 'image/jpeg'
    };
    var personInfo = {
        name : 'David',
        age: 16
    };
    
    var fdata = new FormData();
    fdata.append('personInfo', {
        "string": JSON.stringify(personInfo), //This is how it works :)
        type: 'application/json'
    });
    
    fdata.append('image', {
        uri: img.uri,
        name: img.name,
        type: img.type
    });
    

    【讨论】:

    • 有效!如果没有这个解决方案,所有请求都使用 Content-Type: application/octet-stream 而不是 multipart/form-data 发送。
    【解决方案7】:

    您可以使用 react-native-image-pickeraxios (form-data)

    uploadS3 = (path) => {
        var data = new FormData();
    
        data.append('files',
            { uri: path, name: 'image.jpg', type: 'image/jpeg' }
        );
    
        var config = {
            method: 'post',
            url: YOUR_URL,
            headers: {
                Accept: "application/json",
                "Content-Type": "multipart/form-data",
            },
            data: data,
        };
    
        axios(config)
            .then((response) => {
                console.log(JSON.stringify(response.data));
            })
            .catch((error) => {
                console.log(error);
            });
    }
    

    react-native-image-picker

    selectPhotoTapped() {
        const options = {
            quality: 1.0,
            maxWidth: 500,
            maxHeight: 500,
            storageOptions: {
                skipBackup: true,
            },
        };
    
        ImagePicker.showImagePicker(options, response => {
            //console.log('Response = ', response);
    
            if (response.didCancel) {
                //console.log('User cancelled photo picker');
            } else if (response.error) {
                //console.log('ImagePicker Error: ', response.error);
            } else if (response.customButton) {
                //console.log('User tapped custom button: ', response.customButton);
            } else {
                let source = { uri: response.uri };
                 
                // Call Upload Function
                this.uploadS3(source.uri)
    
                // You can also display the image using data:
                // let source = { uri: 'data:image/jpeg;base64,' + response.data };
                this.setState({
                    avatarSource: source,
                });
                // this.imageUpload(source);
            }
        });
    }
    

    【讨论】:

    • 添加 Accept: "application/json" 成功了!
    • { uri: path, name: 'image.jpg', type: 'image/jpeg' } 中的uri 是什么,您使用的是File,因为那里没有记录。你有源文档吗?
    【解决方案8】:

    我一直在寻找解决问题的答案,这就是我的方式

    我使用 expo-document-picker 获取文件

    const pickDocument = async (tDocument) => {
        let result = await DocumentPicker.getDocumentAsync();
        result.type = mimetype(result.name);
        if (result.type === undefined){
          alert("not allowed extention");
          return null;
        }
        let formDat = new FormData();
        formDat.append("file", result);
        uploadDoc(formDat);
      };
    
      const mimetype = (name) => {
        let allow =  {"png":"image/png","pdf":"application/json","jpeg":"image/jpeg", "jpg":"image/jpg"};
        let extention = name.split(".")[1];
        if (allow[extention] !== undefined){
          return allow[extention]
        }
        else {
          return undefined
        }
      }
    
    const uploadDoc = (data) =>  {
        fetch("MyApi", {
          method: "POST",
          body: data
        }).then(res => res.json())
        .then(response =>{
          if (response.result === 1) {
            //somecode
          } else {
            //somecode
          }
        });
      }
    

    这是因为 android 不管理文件的 MIME 类型,所以如果你把标题“Content-type”放在一边,而是把 MIME 类型放在文件上,它会发送正确的标题

    适用于 IOS 和 Android

    【讨论】:

      【解决方案9】:

      我正在使用 Expo SDK 42(react-native v0.63)。我正在使用expo-document-picker 库来选择文档并上传到服务器。

      我假设您想使用FormData 上传某种文件。

      这是我用来打开选择器并获取有关文件的元数据的代码。

      import * as DocumentPicker from 'expo-document-picker';
      
      const result = await DocumentPicker.getDocumentAsync({
          type: 'image/*',
          copyToCacheDirectory: false,
          multiple: false,
      });
      
      if (result.type === 'success') {
          const name_split = result.name.split('.');
          const ext = name_split[name_split.length - 1];
          result.type = helper.get_mime_type(ext);
          delete result.size;
      }
      

      (您可以编写函数以从文件扩展名中获取 mime 类型或使用 npm 中的某些库)

      result此时有以下信息:

      result.uri // "content://path/to/file.ext"
      result.name // filename
      result.type // the mime type of the file such as "image/png"
      

      这是我使用axios库将文件上传到服务器的代码:

      const formdata = new FormData();
      formdata.append('custom_param', 'value');
      formdata.append('file', result); // 'result' is from previous code snippet
      
      const headers = {
          accept: 'application/json',
          'content-type': 'multipart/form-data',
      };
      
      const opts = {
          method: 'POST',
          url: 'your backend endpoint',
          headers: headers,
          data: formdata,
      };
      return await axios.request(axiosopts);
      

      【讨论】:

      • 很好的解释。,解决了我的问题
      【解决方案10】:

      如果您收到 multipart: boundry not found 错误,您可以使用 fetch api 而不是 axios 它适用于 fetch 但由于某种原因不适用于 axios。

      fetch('http://192.168.10.38:8080/api/auth/register',{
       method: 'post',
       headers: {
         'Content-Type': 'multipart/form-data',
        },
       body: formdata
       }).then(response => {
          console.log("success")
       }).catch(err => {
          console.log(err)
      

      })
      });

      【讨论】:

        猜你喜欢
        • 2018-09-12
        • 2020-05-01
        • 1970-01-01
        • 2017-04-07
        • 1970-01-01
        • 1970-01-01
        • 2018-03-28
        • 1970-01-01
        • 2023-02-13
        相关资源
        最近更新 更多