如何在react-native中使用FormData

How to use FormData in react-native?

本文关键字:FormData react-native      更新时间:2023-09-26

我要学会使用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();

这是我的简单代码FormData与react-native post请求与字符串和图像。

我使用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项设置自定义内容类型:

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
});

这对我有用

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'
  })
});

提供其他解决方案;我们也用react-native-image-picker;服务器端采用koa-multer;这个设置工作正常:

ui

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: '',
        };
      }
    });
  }
}

react-native中formdata的用法

我使用react-native-image-picker来选择照片。在我的情况下,从手机选择照片。我存储它的信息在组件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()))

我使用的是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);

可以使用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);
        }
    });
}

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

我使用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

我已经使用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)
      })  
  }
});

如果你得到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)

})
});

适合我。

// imageObject
{
  name: string,
  type: string,
  uri: string,
}
// body  
const formData = new FormData();
formData.append('name', postData.name);
formData.append('properties', {
    string: JSON.stringify(postData.properties),
    type: 'application/json',
});
postData.slides.forEach(v => {
    formData.append('slideImages', v);
  });
formData.append('detailImage', postData.detailImage);
// request
requestInit: {
    method: 'POST',
    body: formData,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'multipart/form-data',
    },
}