导读:小蓝直聘的简历模块,求职者要传头像、传附件简历,还要在网页/小程序里预览 PDF。第一版上传不做压缩,一张 5MB 的照片传半天;第二版加了压缩和统一上传封装,还把简历做成多步表单(基本信息→教育经历→求职期望)。这篇把 uni-app 上传和简历页的落地细节写清楚。
小蓝直聘简历模块:uni.uploadFile 封装 + 图片压缩 + PDF 预览,多步表单一次做对
先说需求。简历模块四块:基本信息(头像+姓名+期望)、教育经历、工作经历、求职期望,页面上有头像上传、附件简历上传(PDF/Word),还要能在线预览。第一版赶工,上传逻辑每个页面复制一份,图片不压缩,用户传一张 5MB 的照片直接卡死。
第一版:上传逻辑散落,图不压缩
最初的写法,每个页面各写各的:
uni.uploadFile({url:BASE_URL+'/file/upload',filePath:tempFilePath,name:'file',success:(res)=>{// 每个页面都重复一遍}})页面一多就乱:有的忘了传 token,有的没处理失败,最要命的是图片不做压缩,原图直接传,5MB 照片走 4G 网络要十几秒。
统一封装:uploadFilePromise,token 带上、失败统一处理
把所有上传收敛到一个公共方法(真实项目里addResume.vue就这么用的):
uploadFilePromise(url){returnnewPromise((resolve,reject)=>{uni.uploadFile({url:BASE_URL+'/api/file/upload',filePath:url,name:'file',header:{token:uni.getStorageSync('token')},success:(res)=>{if(res.statusCode!==200){uni.showToast({title:'上传失败',icon:'none'})reject(res)return}constdata=JSON.parse(res.data)resolve(data.data.fileUrl)// 返回服务器文件 URL},fail:reject})})}header 里必须带 token,这是第一个容易踩的坑——上传接口一般不走请求拦截器,token 要手动塞。
图片压缩:先压再传,5MB 压到 300KB
上传前先压缩,uni.compressImage是官方 API,小程序和 App 都能用:
asyncfunctionuploadAvatar(tempFilePath){letfile=tempFilePath// 大于 500KB 就先压缩constinfo=awaitgetFileSize(tempFilePath)if(info.size>500*1024){constcompressed=awaitnewPromise((resolve,reject)=>{uni.compressImage({src:tempFilePath,quality:60,// 质量 60%,肉眼基本无差别success:(res)=>resolve(res.tempFilePath),fail:reject})})file=compressed}constfileUrl=awaitthis.uploadFilePromise(file)returnfileUrl}quality: 60是实测经验值,头像这种图 60% 质量人眼看不出区别,体积能砍掉 90%。注意 compressImage 在小程序端有大小限制(单张最大 20MB),超了要先降采样。
PDF 在线预览:openDocument + web-view 双方案
附件简历预览分两种情况:
// 方案一:openDocument 打开本地缓存(PDF/Word 都行)previewResume(url){uni.showLoading({title:'加载中'})uni.downloadFile({url:url,success:(res)=>{uni.hideLoading()uni.openDocument({filePath:res.tempFilePath,fileType:'pdf',// 必须指定类型,Word 传 docshowMenu:true,// 右上角更多按钮,可转发success:()=>{},fail:(err)=>uni.showToast({title:'打开失败',icon:'none'})})}})}// 方案二:H5 端用 web-view 内嵌预览//iOS 上 openDocument 的 fileType 必须传对,传错了直接 fail 没反应;安卓相对宽容。H5 端没有 openDocument,只能用 web-view 嵌 PDF。
踩坑一:安卓真机上传文件名乱码
现象:安卓手机上传头像,后端收到的文件名是一串乱码,导致文件后缀判断失败,图片存成无后缀文件。
排查过程:uni.uploadFile在安卓端对中文文件名编码有问题,后端拿Content-Disposition解析文件名直接乱码。
定位思路:别依赖前端传的文件名,后端用时间戳/UUID 重新生成文件名,前端文件名只做后缀判断。
最终解决:前端上传时把文件名放进formData单独传(encodeURIComponent编码),后端优先用 UUID 命名,formData里的原始名仅做展示。
踩坑二:压缩后图片还是大,传了一分钟
现象:用户反馈传头像特别慢,查日志发现一张压缩后还有 2MB。
排查过程:quality: 60对大尺寸照片效果有限——压缩质量只影响编码,尺寸不变,4000x3000 的照片压完还是很大。
定位思路:压缩要"尺寸 + 质量"双管齐下,先等比缩放到目标尺寸,再压质量。
最终解决:上传前判断图片宽高,超过 1080px 先用 canvas 等比缩放(uni.getImageInfo拿宽高 + canvas 重绘),再压质量,最后体积稳定在 300KB 内。
可直接复用的要点
- 上传逻辑收敛成
uploadFilePromise统一封装:带 token、统一成功/失败处理、返回文件 URL。 - 图片上传前先缩放再压质量,目标尺寸 1080px + quality 60,体积降 90%。
- PDF 预览:小程序/App 用
uni.openDocument(fileType 必须传对),H5 用 web-view。 - 后端别依赖前端文件名,UUID 重命名,前端原始名走 formData 单独传。
- 多步表单(基本信息→教育→工作→期望)每步单独保存,最后一步提交完整简历,防止用户中途退出丢数据。
项目源码:https://gitee.com/gzqkl/job-uniapp