当前位置:首页 > 娱乐

web文件上传组件

——这行代码我写了十年,上件从IE6时代一路写到Chrome 120。传组每次看到它都觉得讽刺:整个互联网最复杂的上件交互之一,表面上是传组浏览器给开发者的一块免费蛋糕,实际上是上件个布满暗坑的沼泽地。 两年前我接手一个医疗影像系统,传组医生上传300MB的上件DICOM文件,进度条卡在87%就再也不动。传组查了半天,上件是传组Nginx默认的client_max_body_size设成了100MB。这种破事我遇过不下二十回——你以为你在写上传组件,上件其实你在跟服务器配置、传组浏览器安全策略、上件甚至操作系统底层API搏斗。传组 真正动手写一个像样的上件上传组件,第一件事是放弃原生input的默认行为。别指望浏览器替你处理分片、断点续传、文件类型校验。原生控件只能给你一个FileList对象,剩下的全得自己来。File对象里有name、size、type这些基础属性,但你要拿到的其实是底层的Blob数据。用File.slice()方法把大文件切成5MB一块,这招在2012年还是个黑科技,现在已经是上传组件的标配了。 分片上传解决了大文件超时问题,但引入了新麻烦:服务端怎么拼接这些碎片?每个分片得有唯一的uploadId标识,还得带上分片序号。我习惯用SparkMD5计算文件哈希作为uploadId,但这玩意儿在计算1GB文件时会卡死主线程——得放到Web Worker里跑。这种细节没人告诉你,全是用血泪换来的经验。 断点续传更坑。你以为记个已上传分片数就完事了?用户中途换了网络,IP变了,服务端session失效,你存的进度全作废。靠谱的做法是把进度存在localStorage,同时让服务端提供查询接口,根据文件哈希返回已存在的分片列表。但存储空间有限制,5MB的localStorage存不了几个大文件的进度记录。得设计个淘汰策略——只保留最近三天操作过的文件信息。 进度条这个看似简单的东西,实际是性能分水岭。用XMLHttpRequest的upload.onprogress事件拿到的百分比,在慢速网络下会卡顿。想要丝滑的进度动画,得用requestAnimationFrame做节流,每帧只更新一次DOM。但这里有个反直觉的点:进度条不能真实反映速度。你把它做成平滑曲线,用户反而觉得快。这是心理学的范畴了,跟技术无关。 文件类型校验也是个无底洞。扩展名能改,MIME类型能伪造。真要验证,得读文件头几个字节。JPEG以FFD8开头,PNG是89504E47,PDF是25504446——这些魔数我得背到死。但就算你验证了文件头,也挡不住用户上传一个伪装成图片的恶意脚本。真正安全的方案是服务端做病毒扫描,前端校验只是给用户一个友好提示罢了。 最后说上传性能。HTTP/2多路复用解决了并发连接数限制,但分片上传时每个请求的header开销反而成了瓶颈。我试过把分片大小从5MB调到2MB,总耗时反而增加——因为TCP拥塞控制算法还没跑到满速,连接就断了。这种调优没有标准答案,得根据实际网络环境做AB测试。 组件写到最后,你会发现真正有价值的不是代码本身,而是对浏览器、网络、服务器三方博弈的理解。上传组件就像个微缩的分布式系统——客户端分片、服务端重组、中间有无数个可能断掉的链路。每次看到有人用现成的uppy或plupload,我都想说:用吧,省下的时间够你多调两个参数。但要是哪天这些库出了你搞不定的bug,记得回来看看这篇——至少你能知道该从哪个断点开始查。

分享到: