使用RNFetchBlob下载PDF报Download manager错误status code=16问询
问题原因排查
错误码16对应Android DownloadManager的ERROR_HTTP_DATA_ERROR,属于系统下载管理器层面的请求失败,Chrome可正常下载是因为两者的请求环境、权限配置、请求头参数存在差异,你的代码存在以下明确问题:
- 路径拼接依赖的
date、file_ext变量未定义,生成的下载路径非法,DownloadManager无法写入文件 - Android高版本权限适配错误:Android 13及以上
WRITE_EXTERNAL_STORAGE权限已废弃,申请该权限会直接返回拒绝,同时Android 10+分区存储规则限制了公共目录的写入逻辑 - 未配置合法请求头:多数服务端会校验User-Agent、Accept等头信息,系统DownloadManager默认的请求头可能被服务端拦截
- 未适配特殊场景:如果URL是HTTP明文协议、包含未转义的特殊字符、存在301/302重定向、需要携带鉴权信息(Cookie/Token),默认配置的DownloadManager都无法正常处理
可行解决方案
1. 基础配置修正
首先修改android/app/src/main/AndroidManifest.xml:
- 在
application节点添加android:requestLegacyExternalStorage="true",适配Android 10的分区存储过渡规则 - 如果使用HTTP明文URL,添加网络安全配置允许明文流量,或直接改用HTTPS协议的URL
2. 权限逻辑修正
Android 11及以上下载文件到公共Download目录不需要申请存储权限,调整权限申请逻辑:
const checkPermission = async (FILE_URL) => { if (Platform.OS === 'ios') { downloadFile(FILE_URL); return; } // Android版本判断 if (Platform.Version >= 33) { // Android13+无需申请存储权限直接下载 downloadFile(FILE_URL); } else if (Platform.Version >= 29) { // Android10-12 申请存储权限 try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, { title: 'Storage Permission Required', message: 'Application needs access to your storage to download File', } ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { downloadFile(FILE_URL); } else { Alert.alert('Error','Storage Permission Not Granted'); } } catch (err) { console.warn(err); } } else { // 低版本安卓正常申请权限 try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, { title: 'Storage Permission Required', message: 'Application needs access to your storage to download File', } ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { downloadFile(FILE_URL); } else { Alert.alert('Error','Storage Permission Not Granted'); } } catch (err) { console.warn(err); } } };
3. 下载逻辑修正
补全变量定义,添加请求头,改用公共Download目录避免路径权限问题:
const downloadFile = (FILE_URL) => { const { config, fs } = RNFetchBlob; // 改用公共Download目录,不需要额外权限 let RootDir = fs.dirs.DownloadDir; // 补全缺失的date变量定义 const date = new Date(); // 补全PDF后缀,你也可以根据URL动态提取后缀 const file_ext = '.pdf'; let options = { fileCache: true, addAndroidDownloads: { path: RootDir + '/file_' + Math.floor(date.getTime() + date.getSeconds() / 2) + file_ext, description: 'downloading file...', notification: true, useDownloadManager: true, // 允许媒体扫描,下载后可以在文件管理器看到 mediaScannable: true, // 配置MIME类型为PDF mime: 'application/pdf' }, // 添加请求头,模拟Chrome的UA避免被服务端拦截 headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'application/pdf,*/*' // 如果需要鉴权,在这里添加Authorization或者Cookie头,比如: // 'Authorization': `Bearer ${你的Token}` } }; config(options) .fetch('GET', FILE_URL) .then(res => { setDownloading(false); console.log('res -> ', JSON.stringify(res)); alert('Téléchargement terminé'); }) .catch(err => { // 捕获异常方便排查 console.error('下载失败:', err); setDownloading(false); }); };
4. 特殊场景处理
如果以上修改后仍报错,检查以下项:
- 确认URL没有未转义的中文、特殊字符,如有需要先用
encodeURI()转义 - 如果URL存在301/302重定向,可先自行请求一次获取最终地址再传入下载
- 如果是自签名HTTPS证书,可在config中添加
trustAll: true允许所有证书
内容的提问来源于stack exchange,提问作者Samy Tcheikman
相关产品推荐
相关产品推荐

