这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
前言
最近在将一个微信小程序的项目迁移为 H5 项目,在迁移里面的文件上传功能到 H5 时却遇到了一些问题。本文正是对这个文件上传过程的一些研究、跟踪的分析记录。
上传功能的实现
原来小程序里面的文件上传使用了 wx.uploadFile
,传递文件路径 filePath
的同时还传递了 formData
参数。
比较奇怪的是 formData
传递的是一个对象,和 axios
中文件上传配置项不太一样。
查了微信小程序开发文档解释如下,但是这个说明内容十分简略,还是不明代这个 formData
到底是什么?
我的困惑
- 文档上说的”其他额外的 form data“指的是什么,它在 XMLHttpRequest 中什么样的?
- wx.uploadFile 上传在 H5 中是否有等价的实现方式?
这里的困惑在文章末尾的 【结论】 部分有解答
分析过程
采用小程序开发者工具查看文件上传接口发送的 HTTP 请求参数, 不过我这里最新版本的开发工具使用调试器和真机调试都遇到 bug。
调试器无法查看文件上传接口的参数
使用真机调试,发现文件上传接口看到的参数没有文件数据??
最后,采用 light-proxy 抓包跟踪
wx.uploadFile发送的数据包
抓包得到的数据如下
提交的参数使用 --1676634161467
分割为四个部分,前面三部分对应 formData 参数传递的对象,最后绿色部分数据为文件的数据
和代码正好对应上
axios发送的数据包
之前在做 web 端管理平台类项目时也做过类似的文件上传功能,并且文件上传 formData 中也携带过额外的 formData 数据。
使用 chrome 调试工具查看 HTTP 请求
点击 view source
查看原始数据
可以看到有两部分数据,分别为:文件数据、自定义的 formData 数据,和代码正好对应
分析结果
通过上面分析可知:
- filePath 传入的是小程序中文件的路径,经过小程序框架会读取文件转换为 File 文件,放到上传接口的
formData
(XMLHttpRequest 传递的 FormData 对象实例)中 - formData 选项传递的是一个对象,小程序框架会遍历这个对象,将其追加到上面的
formData
中
代码验证
验证步骤为:
- 分别用微信小程序
wx.uploadFile
方法、web 端axios
文件上传(也就是 XMLHttpRequest)方法携带额外 formData 参数进行调用; - 同时,用 Node.js 的 http 模块启动服务端,查看服务端接收结果。
验证服务端接收数据
微信小程序上传文件代码
web 端上传文件代码
Node.js 服务端代码
服务端得到结果分别如下
两者之间区别有二:
- file 文件与额外添加的 aaaa、bbb、ccc 字段先后顺序不一致
- 额外添加的字段不一样,以 aaa 为例,见下图
这里字段先后顺序应该是不影响的,而多余的这个 Content-Type
字段很可能影响服务端对数据的解析,下面进行验证。
验证服务端数据解析
服务端采用 express、connect-multiparty 验证解析后的 FormData 数据。
服务端代码改造为如下:
微信小程序结果
web 端结果
很明显,两者得到的数据一致,但取值方式不同。
微信小程序端上传文件方式携带的额外 formData 数据在 req.body
web 端则在 req.files
怀疑是服务端的 connect-multiparty 中间件对 formData 的解析方式不同导致,继续使用 koa-body 中间件验证。
用koa验证数据解析
微信小程序文件上传时服务端接收数据
web 端上传时服务端接收到数据
和上面 express 方式验证结果保持一致。
结论
文档上说的 ”其他额外的 form data“ 相当于在 XMLHttpRequest 的 formData 中使用 formData.append()
方法追加额外的数据,不过这个追加过程是遍历对象进行追加的。
wx.uploadFile 上传在 H5 的等价实现方式也呼之欲出,经上述验证还存在服务端数据解析不一致问题,后续再分析。
上图中的写法可看做是一个近似的写法,能实现 multipart/form-data 方式上传文件过程中携带额外的数据,但是服务取值端方式和 wx.uploadFile 不太一致
总结
以抓包分析、实际代码验证的思路分析了微信小程序 wx.uploadFile
方法的近似实现过程,对 XMLHttpRequest 文件上传的过程有了更进一步的了解。
不足的是:本次分析中还并未找到 H5 中对 wx.uploadFile
方法的完美等价写法。另外还可以借由此文思路进一步探索微信小程序框架是如何对 wx.uploadFile
方法进行封装的,以及是否可按照其思路对 H5 中文件上传进行一定封装。