Nativescript Angular iOS上传文件遇NSURLErrorDomain Code=-1001超时求助
解决NativeScript Angular iOS低速网络上传超时问题
针对NSURLErrorDomain Code=-1001请求超时错误,可通过以下几种方案解决:
1. 延长HTTP请求超时时间
Angular HttpClient默认超时较短,低速网络下上传大文件容易触发超时,可通过RxJS的timeout操作符为单个请求设置更长超时:
import { timeout } from 'rxjs/operators'; upload(photosData: PhotoWrapper): Observable<PhotoResult> { let headers = this.authService.getAuthHeader(); // 设置5分钟超时(300000毫秒),根据实际需求调整 const timeoutMs = 300000; return this.http.post<boolean>(this.configurationService.uploadPhotoUrl(), photoDto, { headers: headers, observe: 'response' }) .pipe( timeout(timeoutMs), map((result)=>( {flag: result.body, wrapper: photosData} as PhotoResult)) ); }
2. 限制并发上传数量
当前代码使用zip和forkJoin同时上传所有文件,低速网络下并发过多会分摊带宽,导致单个请求超时。可改用mergeMap限制并发数,比如一次仅上传2个文件:
// 替换uploadPhotos方法中的zip逻辑 import { from } from 'rxjs'; import { mergeMap, scan } from 'rxjs/operators'; // ... if (this.photos !== null && this.photos.length > 0) { const photosList$ = new Array<Observable<boolean[]>>; this.photos.forEach(photo=> { const observable = this.submitPhoto(photo) if (observable) { photosList$.push(observable); } }); from(photosList$).pipe( mergeMap(obs => obs, 2), // 限制同时上传2个文件 scan((acc, current) => { // 累计上传失败和成功数量 acc[0] += current.filter(f => !f).length; acc[1] += current.filter(f => f).length; return acc; }, [0, 0]) ).subscribe(([notuploaded, uploaded]) => { this.message = `Uploaded ${uploaded} Photo(s).`; if (notuploaded > 0) { this.message += ` Errors uploading ${notuploaded}`; } }); }
3. 添加超时重试机制
针对临时网络波动导致的超时,可通过retryWhen操作符实现重试逻辑,避免单次超时直接失败:
import { timeout, retryWhen, delay, scan } from 'rxjs/operators'; upload(photosData: PhotoWrapper): Observable<PhotoResult> { let headers = this.authService.getAuthHeader(); const timeoutMs = 300000; const maxRetries = 2; // 最多重试2次 return this.http.post<boolean>(this.configurationService.uploadPhotoUrl(), photoDto, { headers: headers, observe: 'response' }) .pipe( timeout(timeoutMs), retryWhen(errors => errors.pipe( scan((retryCount) => { if (retryCount >= maxRetries) { throw new Error('Max retries exceeded'); } return retryCount + 1; }, 0), delay(1000) // 重试前延迟1秒,给网络恢复时间 ) ), map((result)=>( {flag: result.body, wrapper: photosData} as PhotoResult)) ); }
4. 优化文件上传格式,避免Base64转码
Base64会使文件体积增大30%,大幅增加上传时间。改用FormData直接上传二进制文件,减少数据传输量:
upload(photosData: PhotoWrapper): Observable<PhotoResult> { let headers = this.authService.getAuthHeader(); // 移除手动设置的Content-Type,让客户端自动处理multipart/form-data边界 headers.delete('Content-Type'); const formData = new FormData(); // 直接添加本地文件到FormData(假设photosData.File是NativeScript的File对象) formData.append('photo', photosData.File, photosData.File.name); // 如需上传元数据,可添加JSON字段 formData.append('photoMetadata', JSON.stringify({ id: photosData.id, uploaded: photosData.Uploaded })); const timeoutMs = 300000; return this.http.post<boolean>(this.configurationService.uploadPhotoUrl(), formData, { headers: headers, observe: 'response' }) .pipe( timeout(timeoutMs), map((result)=>( {flag: result.body, wrapper: photosData} as PhotoResult)) ); }
5. iOS原生层面调整NSURLSession超时
NativeScript底层依赖iOS的NSURLSession,可全局配置更长的超时时间:
import { ios } from '@nativescript/core'; // 在应用初始化时(比如app.ts)添加以下代码 if (ios) { const sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration(); // 设置单个请求超时(秒) sessionConfig.timeoutIntervalForRequest = 300; // 5分钟 // 设置整个资源传输的超时(秒) sessionConfig.timeoutIntervalForResource = 600; // 10分钟 // 替换默认的URLSession NSURLSession.sharedSession = NSURLSession.sessionWithConfigurationDelegateDelegateQueue(sessionConfig, null, null); }
建议组合使用上述方案,比如二进制上传+延长超时+限制并发+重试,能最大程度降低低速网络下的超时概率。
内容的提问来源于stack exchange,提问作者Pein
相关产品推荐
相关产品推荐

