首先,你要先熟悉并了解HTTP底层原理。
从微信官方在文档里角度是这样划分的:
wx.request
→ 普通 HTTP 请求(JSON、表单字段)。
wx.uploadFile
→ 专门用于文件上传。换句话说:
wx.request
没有“封装层”去处理 multipart/form-data 的复杂性。因此,从“理论规则”上来说
wx.request
并不能上传文件。
分析
wx.request 为什么不能上传文件?
-
从HTTP协议角度来说,只要能发送一个HTTP请求能传入一个文件。上传文件本质就是一个 HTTP POST 请求,body 里用 multipart/form-data 格式,把文件二进制流塞进去。所以只要能发 HTTP,就“理论上”能上传文件
-
但是微信小程序运行环境下,只能用wx.request这个API,所以网络请求就只能用微信提供的这个API
-
你可以把请求头的Content-Type改成multipart/form-data格式,这个格式是协议上传文件的,但是微信不会帮你处理 boundary、文件名、Content-Disposition 等协议部分
-
其次,wx.request的data属性只支持string/object/ArrayBuffer这三个类型:如果是object就会自动序列化成 JSON 或 application/x-www-form-urlencoded;如果是string就原样发;如果是ArrayBuffer就当成原始 body 发,但不会自动帮你拼 multipart/form-data协议格式
那为什么不能用axios或ajax等第三方网络请求库?
-
首先我们要先了解这些网络请求库是怎么实现的,这些网络请求库其实只是为了方便开发者使用调用,提供一些常用方法或者一些现成的方法工具。无论如何他的底层都是要用到环境底层的网络请求API,例如XMLHttpRequest/fetch。总结来说,他们只是对XMLHttpRequest/fetch的封装
-
首先我们这个文档讨论的是微信小程序这类小程序运行环境,并不是API齐全和丰富的浏览器环境
-
这类小程序的运行环境,虽然本质也是浏览器二改的。但这是被二改过的环境,会删除一些API或者无用的API,专门为小程序这种环境精简过的环境
-
也就是所谓的微信小程序“沙箱”环境,微信在底层拦截了网络请求,只允许走它的网络栈。他只允许使用他自己提供的wx.request API去发送网络请求
-
虽然有社区的人根据axios的调用方式写了专门用于小程序环境的工具库,因为小程序的“沙箱”环境根本就是没有XMLHttpRequest/fetch,所以axios这类网络请求工具,它本质还是用wx.request API,所以就根本没办法逃脱出上一个问题
那该怎么上传文件?
-
微信为了安全和控制流量,强制所有网络走它自己设计的 API
-
因此,微信从底层API上设计了两个API,就是wx.request和wx.uploadFile,一个就是为了发普通数据的网络请求,一个则专门是用来上传文件的
-
所以,如果是上传文件就调用wx.uploadFile,它里面专门处理请求头信息,以及multipart/form-data协议格式
能不能多文件上传,该怎么解决?
-
在微信小程序里一次上传多个文件,官方 API wx.uploadFile 设计上只支持单个文件
-
一次只能上传一个文件,这是微信 API 的限制
-
如果你一定要“一次请求”上传多个文件,那就得自己拼 multipart/form-data,走 wx.request,但那就回到前面我们说的手动拼协议,非常麻烦了
-
主流现行方案都是一个一个上传,比如9张照片循环调用wx.uploadFile,用Promise.all包住。但是需你手动限制和控制上传请求的并发数,因为微信文档来说,wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个
-
极为少见且少用的方案是把所有图片转成base64,以wx.request API的对象形式提交,缺点很明显,对小程序运行设备内存有很大要求,如果转化过程是要放在小程序内存里的,一般我们也不能这样做。而且Base64 会让数据体积 膨胀大约33%左右,转成字符串后会占用大量内存(JS 引擎里字符串要额外开销)。对低端手机、微信沙箱环境非常吃内存,容易 OOM / 卡死 / 请求失败,而且小程序本身有 单次请求体积限制(10MB 左右),所以大文件基本跑不通。Base64 编解码本身也要 CPU 运算,在低端机上转换大文件会卡顿。JSON 序列化/反序列化也会变慢
结论
-
不是说 wx.request 技术上绝对不能上传文件,而是它 没提供“易用的文件上传能力”
-
硬要用 wx.request 上传文件,也可以读文件转ArrayBuffer,自己拼 multipart/form-data 协议(boundary、headers、文件内容)。这样是可行的,但写起来很麻烦,而且这需要你对multipart/form-data 协议格式很熟练熟悉
-
微信官方才会推荐你用wx.uploadFile,因为它天然帮你解决了 90% 的麻烦
-
wx.request 不支持文件上传是因为它设计时只负责 JSON/表单请求,没有内建 multipart/form-data 的封装和进度支持;真正的上传需求要用 wx.uploadFile
-
微信小程序里 没有 DOM、没有 XHR、没有 fetch,整个运行时不是浏览器,小程序环境也更没有浏览器的 XHR/fetch,axios或ajax等库在小程序里用的时候,本质都是“封装 + 适配器”,底层调用wx.request
-
boundary / Content-Disposition / Content-Type 是标准的 multipart/form-data 协议字段,方便后端自动解析。你要是跟后端约定了自己的协议(比如“直接传裸二进制,不加 boundary”),那当然没问题。但代价是:你们要写自定义解析逻辑,不能用框架的现成解析器。
-
如果后端走的是现成框架(比如 Spring MVC、Express、Django、Thinkphp),它们默认是用multipart/form-data协议标准去解析上传的文件的,你不按标准来,框架就直接解析失败。因此后端可能也需要做特殊处理。
方案
-
老老实实用官方提供的API和方案走
-
自己去网上查,如上我已经举例很多了
看完是不是感觉又涨“芝士”了,还不点这个赞?