Ionic 5 Capacitor对接PHP服务端实现文件下载的问题求助
问题原因排查
第一种方案报错原因
- 401状态码属于未授权错误:Cordova FileTransfer插件不会自动携带你应用全局的认证凭证(如Cookie、Authorization请求头),所以请求被服务端拦截。
- 额外说明:Cordova FileTransfer插件早已停止维护,Capacitor环境下完全不推荐使用。
第二种方案“文件未保存”原因
日志已经明确返回文件写入成功的路径,实际文件已经保存,只是保存在应用专属沙盒目录:
- 你使用的
externalDataDirectory(安卓)、documentsDirectory(iOS)都是应用私有目录,普通用户无法通过系统文件管理器直接查看 - 你直接将
arraybuffer类型传入写入方法,部分版本的Cordova File插件存在类型兼容问题,可能导致文件损坏
可行解决方案
步骤1:优先切换为Capacitor官方维护的@capacitor/filesystem插件,避免兼容问题
先安装插件:
npm install @capacitor/filesystem npx cap sync
步骤2:添加平台配置使下载文件可见
安卓配置(android/app/src/main/AndroidManifest.xml)
添加对应存储权限:
<!-- 安卓13及以上 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 安卓12及以下 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
iOS配置(Info.plist)
添加配置使文件在系统“文件”App可见:
<key>UIFileSharingEnabled</key> <true/> <key>LSSupportsOpeningDocumentsInPlace</key> <true/>
步骤3:修正下载代码
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; import { firstValueFrom } from 'rxjs'; // 如果你用Angular HttpClient的话 async download(fileURL: string, filename: string) { await this.platform.ready(); try { // 1. 发请求拿文件数据,用你全局的HttpClient,自动携带认证信息 const fileData = await firstValueFrom( this.http.get(encodeURI(fileURL), { responseType: 'blob' }) ); // 2. Blob转Base64适配Filesystem插件 const base64Data = await this.convertBlobToBase64(fileData) as string; // 3. 写入公共下载目录,用户可直接在文件管理器查看 const savedFile = await Filesystem.writeFile({ path: filename, data: base64Data, directory: Directory.Downloads, // 直接写入系统公共下载目录 recursive: true }); console.log('文件保存成功,路径:', savedFile.uri); } catch (err) { console.error('下载失败:', err); alert('下载失败:' + JSON.stringify(err)); } } // Blob转Base64工具方法 private convertBlobToBase64(blob: Blob): Promise<string | ArrayBuffer | null> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = reject; reader.onload = () => { resolve(reader.result); }; reader.readAsDataURL(blob); }); }
步骤4:服务端PHP代码优化
修正路径不一致问题,同时避免路径遍历漏洞:
//used for download attachment header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Headers: *'); header("Access-Control-Allow-Methods: GET"); $varFile = basename($_GET['file']); // 用basename过滤,避免路径遍历 $varDir = ($_GET['dir'] != '') ? trim($_GET['dir'], '/') . '/' : ''; // 统一路径变量 $varFilePath = $arrConfig['sourceRoot'] . $varDir . $varFile; if (file_exists($varFilePath)) { header("Pragma: public"); header("Expires: 0"); header("Content-Description: File Transfer"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header('Content-Type: application/octet-stream'); header("Content-Disposition: attachment; filename=" . $varFile); header("Content-Transfer-Encoding: binary"); header("Content-Length: " . filesize($varFilePath)); @readfile($varFilePath); exit(); }
内容的提问来源于stack exchange,提问作者Deepak Dholiyan
相关产品推荐
相关产品推荐

