关于React Native使用formData形式上传文件失败,请求失败报错:Net Error问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于React Native使用formData形式上传文件失败,请求失败报错:Net Error问题相关的知识,希望对你有一定的参考价值。
参考技术A 造成这个问题的原因是 React Native 0.62 后增加了对Flipper的支持。Flipper是一个移动APP的调试工具,由于默认支持的Flipper的版本低,存在兼容问题。导致调试模式下会出现上传文件发送请求失败的情况。使用新版本Flipper替换旧版本。具体操作如下:
如何在 react-native 中使用 FormData?
【中文标题】如何在 react-native 中使用 FormData?【英文标题】:How to use FormData in react-native? 【发布时间】: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-nativemake sure not to have the react-native debugger attached
中处理 FormData 时。否则你会有问题。
【参考方案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,它不在里面 FormData 是 react-native 自带的。 github.com/facebook/react-native/blob/master/Libraries/Network/… 根据 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-picker 和 axios (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)
) );
【讨论】:
以上是关于关于React Native使用formData形式上传文件失败,请求失败报错:Net Error问题的主要内容,如果未能解决你的问题,请参考以下文章
将 react-native-signaturepad 输出转换为 formData?
FormData发送字符串值而不是react-native中的视频文件
React Native:无法在“FormData”上执行“附加”:参数 2 不是“Blob”类型。在新的 ApolloError