如何在React Native中用axios、XHR、fetch实现JSON数据上传进度展示
问题核心原因
React Native 内置的 XMLHttpRequest 实现对非 multipart/form-data 类型的POST请求,默认不会触发upload progress事件,axios底层调用RN的XHR能力,因此你提供的两种写法都无法正常获取上传进度。
可行解决方法
方案1:改用multipart/form-data格式上传(适配现有API成本最低)
你可以将原本的JSON载荷拆分填充到FormData对象中,base64格式的图片可直接作为普通字段传入,RN会针对FormData类型的请求正确触发上传进度事件。
XMLHttpRequest版本实现
function handleEvent(e) { // 先判断长度是否可计算,避免出现NaN if (e.lengthComputable) { setProgress(Math.round((e.loaded / e.total) * 100)) } } const formData = new FormData(); // 将原有payload的字段逐个填充到FormData Object.keys(payload).forEach(key => { formData.append(key, payload[key]); }); const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', handleEvent); xhr.open("POST", url); xhr.setRequestHeader("Accept", "application/json"); // 无需手动设置Content-Type,RN会自动生成带boundary的正确请求头 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { console.log(xhr.status); console.log(xhr.responseText); } }; xhr.send(formData);
axios版本实现
需要额外添加transformRequest配置,避免axios自动转换FormData格式:
const formData = new FormData(); Object.keys(payload).forEach(key => { formData.append(key, payload[key]); }); var res = await axios.post(BASE_URL + '/crossstorage_addfile', formData, { headers: { 'Content-Type': 'multipart/form-data', ...headers }, transformRequest: (data) => data, onUploadProgress: function (progressEvent) { if (progressEvent.lengthComputable) { var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total) console.log(percentCompleted) } } });
方案2:必须保留JSON上传格式,使用专用原生上传库
如果业务要求必须发送application/json格式的请求,可以使用react-native-blob-util库,它绕过RN内置XHR的限制,支持所有请求格式的进度监听:
import RNFetchBlob from 'react-native-blob-util'; RNFetchBlob.fetch('POST', url, { 'Accept': 'application/json', 'Content-Type': 'application/json', }, JSON.stringify(payload)) // 每100ms回调一次上传进度 .uploadProgress({ interval : 100 }, (written, total) => { const progress = Math.round((written / total) * 100); setProgress(progress); }) .then((res) => { const response = res.json(); // 处理响应逻辑 }) .catch(err => { // 处理异常逻辑 })
注意事项
- 开发环境下如果开启了「Debug Remote JS」,XHR请求会被代理拦截,导致进度事件不触发,测试时请关闭远程调试或打release包验证
- 服务器端需要正确返回
Content-Length响应头,否则会出现lengthComputable为false的情况,无法计算进度百分比
内容的提问来源于stack exchange,提问作者Sanjay Kochrekar
相关产品推荐
相关产品推荐

