news 2026/9/21 1:23:39

uni-app X 文件上传完全指南:uni.uploadFile 参数、UploadTask 与跨端实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
uni-app X 文件上传完全指南:uni.uploadFile 参数、UploadTask 与跨端实现原理
  • 示例工程
  • 前端
  • 移动开发
  • 跨平台

【免费下载链接】uni-app

A cross-platform framework using Vue.js

项目地址:https://gitcode.com/gh_mirrors/un/uni-app
点击查看免费下载

本文围绕 uni-app X 的uni.uploadFile接口展开,系统讲解其调用方式、options 全部参数、返回的 UploadTask 对象、错误码体系,并结合本仓库中的 uts 源码与自动化测试页面,深入说明 Android/iOS/HarmonyOS/Web/微信小程序各端的上传实现原理与注意事项。读完本文,你将掌握如何在 uni-app X 工程中完成单文件上传、多文件上传、进度监听、中断上传、Cookie 携带与 User-Agent 定制,并能对照源码定位上传问题。

uni.uploadFile(options)用于将本地资源(图片、视频、文件等)上传到开发者服务器。它在 uni-app X 中位于网络模块uni-network(仓库内实现位于 src/uni_modules/uni-network),该模块在 package.json 中声明了requestuploadFiledownloadFileconfigMTLS四个面向 App 端的扩展接口,其中uploadFile在 Android(Kotlin)、iOS(Swift)、HarmonyOS(ArkTS)均有原生实现。

官方推荐将文件上传到 uniCloud,uniCloud 提供了更便宜的 CDN 与更好的易用性;若使用自有服务器,则按本文所述方式将本地资源通过 multipart/form-data 表单提交到后端接口。

一、接口签名与兼容性

uni.uploadFile(options: UploadFileOptions): UploadTask

在仓库源码 src/uni_modules/uni-network/utssdk/interface.uts 中,上传接口的类型定义如下:

export type UploadFile = (options: UploadFileOptions) => UploadTask;

各端最低支持版本(对应文档 docs/api/upload-file.md 中的兼容性表格):

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | 4.0 | 4.41 | 3.91 | 4.11 | 4.61 |

说明:unixVer(uni-app x 版本)在 Web 端为 4.0、微信小程序端为 4.41、Android 为 3.91、iOS 为 4.11、HarmonyOS 为 4.61;这些版本号同时出现在源码注释的@uniPlatform标记中,与文档保持一致。

二、options 参数详解

options的类型为UploadFileOptions,其完整定义见 interface.uts。全部参数如下:

| 名称 | 类型 | 必备 | 默认值 | 描述 | | :- | :- | :- | :- | :- | | url | string | 是 | 无 | 开发者服务器地址 | | filePath | string | 否 | null | 要上传文件资源的路径,支持uni.env| | name | string | 否 | "file" | 文件对应的 key,服务端通过该 key 读取文件二进制内容 | | files | Array<UploadFileOptionFiles> | 否 | null | 需要上传的文件列表 | | header | UTSJSONObject | 否 | null | HTTP 请求 Header,header 中不能设置 Referer | | formData | UTSJSONObject | 否 | null | HTTP 请求中其他额外的 form data | | timeout | number | 否 | 120000 | 超时时间,单位 ms | | success | (result: UploadFileSuccess) => void | 否 | null | 成功回调 | | fail | (result: UploadFileFail) => void | 否 | null | 失败回调 | | complete | (result: any) => void | 否 | null | 结束回调(成功、失败都会执行) | | enableHttp2 | boolean | 否 | 无 | 仅微信小程序(基础库 2.10.4+):是否开启 http2 | | enableProfile | boolean | 否 | 无 | 仅微信小程序(基础库 3.5.0+):是否开启 profile,iOS 与 Android 端默认开启,开启后可在 res.profile 中查看性能调试信息 | | enableQuic | boolean | 否 | 无 | 仅微信小程序(基础库 2.10.4+):是否开启 Quic/h3 协议 |

2.1 必填参数的源码校验

从协议层看,url是唯一必填参数。仓库 src/uni_modules/uni-network/utssdk/protocol.uts 中定义了UploadFileApiProtocolUploadFileApiOptions

  • 协议声明中urlrequired: truefilePathnameheaderformDatatimeout均为可选;
  • 格式化阶段,若url为空直接抛出'url is required'
  • name为空,则补默认值'file'

这一逻辑与文档中的默认值表完全对应,即不传name时表单字段名固定为file

2.2 files 数组元素 UploadFileOptionFiles

当需要一次上传多个文件时,使用files数组,其元素属性(interface.uts):

| 名称 | 类型 | 必备 | 默认值 | 描述 | | :- | :- | :- | :- | :- | | name | string | 否 | "file" | multipart 提交时的表单项目名。若 name 不填或填的值相同,服务端读取文件时可能只能读取到一个文件 | | uri | string | 是 | 无 | 要上传文件资源的路径 | | file | any | 否 | 无 | 要上传的文件对象(Web 端支持,App 端 Android/iOS 支持,HarmonyOS 暂不支持) |

2.3 filePath 与 uni.env

filePath支持uni.env中的环境变量路径。典型用法是先下载到应用私有目录,再上传:

const filePath = `${uni.env.USER_DATA_PATH}/uni-app.png` uni.downloadFile({ url: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-app.png", filePath: filePath, success: () => { uni.uploadFile({ url: 'https://unidemo.dcloud.net.cn/upload', filePath: filePath, name: 'file', success: () => { console.log('上传成功') }, fail: () => { console.log('上传失败') } }) } })

需要注意:微信小程序只支持USER_DATA_PATH,且子目录未创建的情况下不能直接下载到子目录内(该注释同样出现在 src/pages/API/upload-file/upload-file.uvue 的自动化测试例中)。

三、成功与失败回调的结构

3.1 UploadFileSuccess

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | data | string | 是 | 开发者服务器返回的数据 | | statusCode | number | 是 | 开发者服务器返回的 HTTP 状态码 | | profile | UploadFileSuccessProfile | 否 | 网络请求调试信息(微信小程序基础库 3.5.0+,iOS/Android 支持) |

profile中包含完整的网络性能时间线字段:fetchStartrequestStartrequestEndresponseStartresponseEndconnectStartconnectEnddomainLookUpStartdomainLookUpEndSSLconnectionStartSSLconnectionEndredirectStartredirectEndrttthroughputKbpsdownstreamThroughputKbpsEstimatehttpRttEstimatetransportRttEstimateprotocol(http1.1/h2/quic/unknown)、peerIPportsendBytesCountreceivedBytedCountsocketReusedqueueStartqueueEndinvokeStartusingHighPerformanceModeestimate_nettypehttpDNSDomainLookUpStarthttpDNSDomainLookUpEnd等,可用于定位网络瓶颈与判断是否走了高性能模式。

3.2 UploadFileFail 与错误码

失败对象结构:

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | errCode | number | 是 | 错误码 | | errSubject | string | 是 | 统一错误主题(模块)名称 | | data | any | 否 | 错误信息中包含的数据 | | cause | Error | 否 | 源错误信息(可包含多个错误,详见 SourceError) | | errMsg | string | 是 | 错误信息 |

errCode合法值及含义(与 src/uni_modules/uni-network/utssdk/unierror.uts 中的错误码表一一对应):

| errCode | 描述 | | :- | :- | | 5 | 接口超时 | | 1000 | 服务端系统错误 | | 100001 | json 数据解析错误 | | 100002 | 错误信息 json 解析失败 | | 100003 | json 解析类型转换失败 | | 600003 | 网络中断 | | 600008 | data 参数类型不合法 | | 600009 | URL 格式不合法 | | 600010 | Cronet 模块加载失败 | | 602001 | request 系统错误 |

其中5(超时)与1000(服务端系统错误)并非原生层直接返回,而是在 app-android/index.uts 的监听器中对原始错误信息做二次映射得到的:错误信息包含timeout时归为5causeConnection refused时归为1000,含Network is unreachable时归为600003,含invalid URL时归为600009。iOS 端实现位于 app-ios/index.uts,HarmonyOS 端实现位于 app-harmony/index.uts,错误处理语义保持一致。

四、返回值 UploadTask 与上传生命周期

uni.uploadFile返回一个UploadTask对象(interface.uts),用于控制上传任务:

| 方法 | 签名 | 描述 | | :- | :- | :- | | abort | abort(): void | 中断上传任务 | | onProgressUpdate | onProgressUpdate(callback: UploadFileProgressUpdateCallback): void | 监听上传进度变化 |

onProgressUpdate的回调参数OnProgressUpdateResult

| 名称 | 类型 | 描述 | | :- | :- | :- | | progress | number | 上传进度百分比 | | totalBytesSent | number | 已经上传的数据长度(Bytes) | | totalBytesExpectedToSend | number | 预期需要上传的数据总长度(Bytes) |

从 Android 实现看,UploadController.uploadFile(src/uni_modules/uni-network/utssdk/app-android/network/upload/UploadController.uts)使用 OkHttp 的MultipartBody构建 multipart/form-data 请求体,通过ProgressRequestBody包装实现进度上报,并在NetworkUploadProgressListener.onProgress中按(bytesWritten / contentLength) * 100计算百分比,同时给出已发送字节数与总字节数。abort()对应底层call.cancel()onProgressUpdate则把回调注册进监听器的progressListeners列表,由NetworkUploadFileListener.onProgress分发。

4.1 iOS 4.25 版本注意事项:Task 对象自动销毁

在 4.25 版本起,iOS 平台增加了 Task 原生对象自动销毁的逻辑:上传完成后会自动释放原生的 Task 对象。建议开发者在complete回调中置空 Task 对象:

complete: () => { this.task = null }

如果不释放,之后继续调用 Task 对象的方法会导致控制台报错:error: instance object does not exist: id:15

五、完整示例:选择图片并上传

以下示例取自 hello uni-app x 的官方演示(仓库内对应页面为 src/pages/API/upload-file/upload-file.uvue,模板部分见 docs/api/upload-file.md),展示"选择图片 → 显示加载态 → 上传 → 展示结果 → 释放 Task"的完整闭环:

<script setup lang="uts"> type DataType = { title: string; imageSrc: string; task: UploadTask | null; } const data = reactive({ title: 'uploadFile', imageSrc: '', task: null, } as DataType) onUnload(() => { data.imageSrc = ''; uni.hideLoading(); data.task?.abort(); }) const chooseImage = () => { uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album'], success: (res) => { console.log('chooseImage success, temp path is', res.tempFilePaths[0]) var imageSrc = res.tempFilePaths[0] uni.showLoading({ title: '上传中' }) data.task = uni.uploadFile({ url: 'https://unidemo.dcloud.net.cn/upload', //仅为示例,非真实的接口地址 filePath: imageSrc, name: 'file', formData: { 'user': 'test' }, success: (res) => { console.log('uploadImage success, res is:', res) uni.showToast({ title: '上传成功', icon: 'success', duration: 1000 }) data.imageSrc = imageSrc }, fail: (err) => { console.log('uploadImage fail', err); uni.showModal({ content: err.errMsg, showCancel: false }); }, complete: (res) => { uni.hideLoading(); data.task = null } }); }, fail: (err) => { console.log('chooseImage fail', err) } }) } </script>

关键点:

  • onUnload中调用data.task?.abort()中断未完成的上传,防止页面退出后请求仍在进行;
  • complete中置空data.task,符合 iOS 4.25 起 Task 自动释放的要求;
  • fail回调中通过err.errMsg展示错误,便于用户理解失败原因。

六、进阶实战:多文件上传与请求头定制

6.1 多文件上传(files)

一次上传多个文件时使用files数组,务必为每个元素指定不同的name,否则服务端可能只能读取到一个文件:

uni.uploadFile({ url: 'https://unidemo.dcloud.net.cn/upload', files: [ { name: "file1", uri: imageSrc } as UploadFileOptionFiles, { name: "file2", uri: imageSrc } as UploadFileOptionFiles ], success: (res: UploadFileSuccess) => { if (res.statusCode == 200) { console.log('上传成功') } }, fail: () => { console.log('上传失败') }, })

从 Android 源码 UploadController.uts 可以看到,filesfilePath是互斥的两条分支:优先遍历files数组逐个构造addFormDataPart(name, fileName, requestBody);若files为空再回退到filePath分支。任一文件的路径非法(无法打开输入流)都会直接触发fail(错误信息为 "Illegal file")。

6.2 定制 User-Agent

header支持自定义请求头,例如覆盖User-Agent。仓库测试页面中的jest_uploadFileVerifyUA验证了该能力:上传到回显接口后,从响应 JSON 中取出requestHeaders['user-agent'],校验其数量为 1(即自定义值生效且未追加默认 UA)。

对应 Android 实现 UploadController.uts:遍历header时检测是否已含User-Agent(忽略大小写),若开发者未提供则自动补上 WebView 的 UA。因此当你在header中指定"User-Agent": "custom"时,最终请求只会携带这一个 UA 值。

uni.uploadFile({ url: 'https://request.dcloud.net.cn/api/http/header/upload', header: { "User-Agent": "custom" }, formData: { 'user': 'test' }, success: (res: UploadFileSuccess) => { // 从 res.data 解析出 requestHeaders,校验 user-agent } })

注意:header 中不能设置 Referer。

6.3 仅携带 formData、不传文件

uploadFile也允许不传任何文件、仅提交表单字段(仓库测试例jest_uploadFileWithoutFile即为此场景)。但 Android 端源码 UploadController.uts 规定:formDatafilePathfiles三者必须至少提供一个,否则直接以错误码602001(request system error)结束任务。

七、Web 端上传的特殊限制

Web 端(uni-app x 的unixVer4.0 起支持)上传文件时,只能使用 downloadFile、chooseImage 等返回文件对象(File 对象)的接口返回值作为要上传的文件,即通过files[].file传入文件对象,而不能直接传磁盘路径字符串。这一点体现在UploadFileOptionFiles.file字段的兼容性上:该字段 Web 端为 4.0 起支持,而uri字段 Web 端标记为x(不支持)。

八、底层实现一览(源码导读)

uni.uploadFile在 App 端由 uts 插件uni-network提供原生能力,各端入口与关键文件如下:

| 平台 | 入口 | 核心实现 | | :- | :- | :- | | Android | app-android/index.uts | network/upload/UploadController.uts(OkHttp MultipartBody) | | iOS | app-ios/index.uts | network/upload/UploadController.uts | | HarmonyOS | app-harmony/index.uts | network/uploadFile.uts | | 类型与协议 | interface.uts、protocol.uts | 参数默认值、必填校验、回调类型定义 | | 错误码 | unierror.uts | errCode 与错误主题映射 |

从源码结构看,Android 端上传流程可概括为:

  1. uploadFile()通过NetworkManager.getInstance().uploadFile(options, listener)创建任务(app-android/index.uts);
  2. UploadController依据timeout(默认 120000ms)配置 OkHttp 的 connect/read/write 三段时间,并注入CookieInterceptor以支持 Cookie 携带;
  3. MultipartBody.Builder依次写入formData键值对与文件 part(InputStreamRequestBody支持content://file://unifile://、相对路径与 android_asset 等路径形式);
  4. ProgressRequestBody包装请求体以计算上传进度,异步call.enqueue()发起请求;
  5. 监听器把结果通过 Handler 抛回主线程,触发success/fail/complete回调。

仓库中同时提供了针对上述能力的自动化测试用例(src/pages/API/upload-file/upload-file.test.js 与 upload-file.uvue 内的jest_*系列方法),覆盖单文件上传、uni.env 路径上传、Cookie 携带与清除、多文件上传、UTS 模块调用、无文件上传、UA 定制等场景,可作为回归验证参考。

九、总结与最佳实践

  • 上传前先通过uni.chooseImage/uni.chooseVideo等接口拿到本地资源路径或文件对象,再交给uni.uploadFile
  • 必传url,并按需设置name(默认file)、formDatatimeout;多文件上传使用files并保证name唯一;
  • 善用UploadTaskonProgressUpdate展示上传进度条,abort()在页面卸载或用户取消时中断任务;
  • complete中置空 Task 引用,规避 iOS 4.25 起 Task 自动销毁带来的instance object does not exist报错;
  • 结合fail回调中的errCode(超时 5、URL 非法 600009、网络中断 600003、系统错误 602001 等)快速定位问题;
  • Web 端只能上传由 downloadFile/chooseImage 等接口返回的文件对象;
  • 若追求更低的存储与 CDN 成本、更简单的接入体验,可优先考虑上传到 uniCloud。
  • 示例工程
  • 前端
  • 移动开发
  • 跨平台

【免费下载链接】uni-app

A cross-platform framework using Vue.js

项目地址:https://gitcode.com/gh_mirrors/un/uni-app
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 1:22:39

Vitis 2023.1下LWIP Echo Server与YT8521S PHY调试全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/21 1:22:33

Holtek BS45F3833高集成MCU如何重塑超声波雾化方案设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/21 1:21:25

MXNet Gluon 迁移学习实战:从实验训练到模型部署的完整流程

MXNet Gluon 迁移学习实战&#xff1a;从实验训练到模型部署的完整流程 【免费下载链接】mxnet Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and m…

作者头像 李华
网站建设 2026/9/21 1:19:41

MATLAB批量处理AFM力曲线:从NSMatlabUtilities到全流程自动化实战

接手过一个接近尾声的材料表征项目&#xff0c;那阵子我每天的工作就是对着 Bruker NanoScope Analysis 里的力曲线&#xff0c;一条一条点开、框选基线、找接触点、拟合、导出。单个文件里 Force Volume 测了 3232 个点&#xff0c;一千多条曲线&#xff0c;再乘以十几个样品&…

作者头像 李华
网站建设 2026/9/21 1:16:46

基于555电路与单片机的DC-AC逆变器设计:C语言实现与调试指南

简介&#xff1a;面向有单片机与电力电子基础的研发人员和技术爱好者&#xff0c;这份基于C语言的直流-交流变换器设计实例&#xff0c;围绕555电路与单片机协同实现逆变输出的项目化学习需求展开。文档完整覆盖硬件电路设计&#xff0c;包括电源管理、555定时器、单片机控制、…

作者头像 李华
网站建设 2026/9/21 1:16:14

Cline vs Roo Code:同一把 TaoToken Key 跑完前端重构任务

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华