Ionic 6 如何将本地file/Capacitor协议URL转换为Blob用于API上传
Ionic 6 本地文件URL转Blob的可落地解决方案
核心实现思路
由于iOS WKWebView的同源策略限制,直接通过fetch/XMLHttpRequest读取file://、capacitor://协议的本地文件会触发跨域拦截,同时旧版第三方Base64插件在iOS平台已被废弃,因此采用Capacitor官方原生Filesystem插件读取文件内容,直接转换为可用于FormData上传的Blob对象,全程无废弃API依赖,iOS/Android全平台兼容。
前置准备
- 安装Capacitor官方Filesystem依赖:
npm install @capacitor/filesystem - 同步原生工程配置:
npx cap sync
核心通用转换函数
该函数同时兼容file://、capacitor://两类输入URL,自动解析真实磁盘路径、读取文件内容、生成对应MIME类型的Blob:
import { Filesystem } from '@capacitor/filesystem'; // 常见业务场景的文件MIME类型映射 const MIME_MAP: Record<string, string> = { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif', webp: 'image/webp', pdf: 'application/pdf', doc: 'application/msword', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', xls: 'application/vnd.ms-excel', xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', txt: 'text/plain' }; /** * 本地文件URL转Blob * @param fileUrl 支持两类输入:file协议URL / Capacitor协议URL * @returns 可直接追加到FormData的Blob对象 */ export async function localUrlToBlob(fileUrl: string): Promise<Blob> { // 1. 解析原生层可识别的纯文件路径 let rawDiskPath = ''; if (fileUrl.startsWith('capacitor://')) { // 还原Capacitor协议映射的真实磁盘路径 rawDiskPath = fileUrl.replace('capacitor://localhost/_capacitor_file_', ''); } else if (fileUrl.startsWith('file://')) { // 直接剥离file协议前缀得到磁盘路径 rawDiskPath = fileUrl.replace('file://', ''); } else { throw new Error('不支持的文件URL格式'); } // 2. 通过原生层读取文件内容,无WebView跨域限制 const fileContent = await Filesystem.readFile({ path: rawDiskPath, encoding: 'base64' }); // 3. 将base64编码内容转换为二进制字节数组 const base64 = fileContent.data; const binaryStr = window.atob(base64); const uint8Array = new Uint8Array(binaryStr.length); for (let index = 0; index < binaryStr.length; index++) { uint8Array[index] = binaryStr.charCodeAt(index); } // 4. 根据文件后缀匹配对应MIME类型 const fileSuffix = rawDiskPath.split('.').pop()?.toLowerCase() || ''; const contentType = MIME_MAP[fileSuffix] || 'application/octet-stream'; // 5. 生成标准Blob对象 return new Blob([uint8Array], { type: contentType }); }
接入现有上传逻辑
完全兼容现有FormData上传流程,仅需在生成FormData前调用上述工具函数获取Blob即可,无需改动原有请求封装:
async function uploadBusinessFile(fileUrl: string, fileName: string, uploadUrl: string, authKey: string) { // 调用工具函数拿到Blob const blob = await localUrlToBlob(fileUrl); const formData = new FormData(); formData.append("file", blob); formData.append("name", fileName); formData.append("auth", authKey); return this.api.post(uploadUrl, formData, true); }
常见避坑点
- 不要尝试直接用WebAPI
fetch请求file:///capacitor://格式的URL,iOS WKWebView的安全策略会直接拦截这类跨域请求,抛出CORS错误 - 替换掉原项目中使用的废弃第三方Base64插件,这类插件底层依赖的旧Cordova接口在iOS 14+版本已被官方标记为不推荐使用,存在权限访问失败的问题
- 若需处理超大文件(100M以上),可在读取流程增加分块读取逻辑,避免一次性加载全量内容导致的内存溢出
内容的提问来源于stack exchange,提问作者Milez Zimz
相关产品推荐
相关产品推荐

