问题描述
我最近一直在 React-native 中实现上传文件功能,但遇到了一个错误,我需要将二进制文件数据发布到请求正文中。
首先,我检查了 Postman 的工作原理,并在 postman 中测试了这个 API,我将 Authorization
和 uid
发送到请求标头和 body
将是 Form-Data with document
= binary file
。
见下面的 document
键,我们可以在 Postman 中选择文件对象。
现在这个 Postman 请求以这种方式成功,如果我检查 NodeJs-Axios 的相关代码,它就像在这里添加的一样。
此代码来自 Postman,仅用于解释。
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('document',fs.createReadStream('LOCAL_PATH_TO_FILE/Screenshot 2021-01-28 at 12.26.32 PM.png'));
var config = {
method: 'post',url: 'API_BASE/addDocument/',headers: {
'Authorization': 'Firebase_ID_Token','uid': 'Firebase_User_ID',...data.getHeaders()
},data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
由于我们无法使用上面为 React-native 添加的相同函数,并且我使用了 react-native-document-picker
,因此当我选择任何文件时,我得到的对象就像,
{
"size":1173,"filecopyUri":"file:///Users/Local_File_Path.plist","name":"File_Name.plist","uri":"file:///Users/Local_File_Path.plist"
}
我需要通过 API 调用将此文件(例如 plist)上传到 /adDocument
端点,该端点期望请求正文为 document: (binary data)
。
所以,这是我的 addDocument API 调用 的主要函数,需要对其进行更正以将正确的数据发送到 API。
import RNFetchBlob from 'rn-fetch-blob';
var RNFS = require('react-native-fs');
async uploadFileData (fileData) {
try {
console.log("***** uploadFileData parameters =>>>>> ",fileData);
const mainPath = fileData.uri.replace("file://","");
let readStreamData = await RNFetchBlob.fs.readStream(mainPath,'base64');
let readFileData = await RNFS.readFile(mainPath);
let wrapData = RNFetchBlob.wrap(mainPath);
let data = new FormData();
data.append('document',readStreamData,{'name': fileData.name});
//data.append('document',new Blob([readFileData]),readFileData,{'name': fileData.name});
const apiHeader = {
'Authorization': 'Google_ID_Token','uid': 'Google_User_ID','Content-Type': 'multipart/form-data','Cache-Control' : 'no-store'
};
const res = await axios({
method: 'POST',headers: apiHeader,data: data,baseURL: 'BASE_URL',url: '/addDocument/'
});
console.log("document/addDocument =>>>>> ",res);
return res;
} catch (e) {
console.log("xxxxxxx document/addDocument Error =>>>>> ",e);
return { error: e };
}
}
我总是收到使用上述任何方法 readStreamData
、readFileData
或 wrapData
执行此函数的失败。原因是,我永远无法将二进制数据传递到 document
。
我在请求正文中看到的是,
这里,[object Object]
是一个字符串而不是一个对象,因此,我的 API 调用抛出错误说明,数据丢失。它总是传递我使用'Blob()'的字符串事件。
所以,我想知道我在这里做错了什么,所以我的请求正文没有传递二进制数据。请向我发送有关该主题的任何指示,以便我找到解决方案。
解决方法
这确实是 React-native debugger
的问题,而不是实际的实现问题。正如此处提到的 => https://github.com/jhen0409/react-native-debugger/blob/master/docs/network-inspect-of-chrome-devtools.md,调试器会处理 FormData,并且由于 [object Object]
属性,任何传递到 FormData 的内容都会变成 uri
字符串。
我已关闭调试并在设备和模拟器上进行了尝试,其中以下代码按预期工作。 无需显式将文件转换为 blob。
async simpleFileUpload (fileData) {
try {
console.log("***** uploadFileData parameters =>>>>> ",fileData);
const mainPath = fileData.uri.replace("file://","");
const file = {
uri: mainPath,type: fileData.type,name: fileData.name || fileData.uri.substr(fileData.uri.lastIndexOf('/') + 1)
};
let formData = new FormData();
formData.append('document',file);
const res = await axios({
method: 'POST',headers: this.apiHeaderUpload(),data: formData,baseURL: 'http://103.53.72.244:9091/api',url: '/document/addDocument/'
});
console.log("document/addDocument =>>>>> ",res);
//alert('uploadFileData::Upload Successful >>> ' + JSON.stringify(res));
return res;
} catch (e) {
console.log("xxxxxxx document/addDocument Error =>>>>> ",e);
//alert('uploadFileData::Upload Error >>> ' + JSON.stringify(e));
return { error: e };
}
}
就这么简单:)