vue+axios+van-uploader上传图片Network请求表单数据显示的是formData方法列表?
异常现象:
如题,vue项目中使用van-uploader组件上传图片,Network中查看接口调用荷载的表单数据,没有正常传递图片文件参数,而是一系列函数列表,如下:
append=function%20append()%20%7B%20%5Bnative%20code%5D%20%7D&delete=function%20delete()%20%7B%20%5Bnative%20code%5D%20%7D&get=function%20get()%20%7B%20%5Bnative%20code%5D%20%7D&getAll=function%20getAll()%20%7B%20%5Bnative%20code%5D%20%7D&has=function%20has()%20%7B%20%5Bnative%20code%5D%20%7D&set=function%20set()%20%7B%20%5Bnative%20code%5D%20%7D&entries=function%20entries()%20%7B%20%5Bnative%20code%5D%20%7D&forEach=function%20forEach()%20%7B%20%5Bnative%20code%5D%20%7D&keys=function%20keys()%20%7B%20%5Bnative%20code%5D%20%7D&values=function%20values()%20%7B%20%5Bnative%20code%5D%20%7D&

问题排查:
单独写了原生js上传图片的demo,调用后端接口上传图片成功,示例代码详见:
又写了单独的html页面使用axios上传图片,调用后端接口上传图片也是成功的,示例代码详见:
但唯独在vue项目中一直上传不成功,排除后端接口不支持问题,排除传参格式不一致的问题,那问题很可能出在项目接口请求封装上。
最开始之所以没有怀疑接口请求封装,是因为直接在页面引用了axios,没有走接口调用封装的相关逻辑,但忽略了接口请求封装文件中`transformRequest` 允许在向服务器发送前,修改请求数据的这部分代码。注释掉这部分代码,接口调用成功,那就是这里的问题了。
代码改造:
对请求参数做处理的这部分代码是沿用前边项目的,之前一直也没图片上传功能,所以也就一直没在意。
但现在需要图片上传功能,就不能对请求数据进行任何处理,所以就不能做全局的配置了,考虑在axios示例service的请求拦截器中进行处理。
首先,删掉transformRequest这部分代码:
// `transformRequest` 允许在向服务器发送前,修改请求数据 // axios.defaults.transformRequest = [ // function(data) { // let ret = ""; // for (let it in data) { // ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&"; // } // return ret; // } // ];
然后,给axios示例service添加请求拦截器:
// 请求拦截器 - 用于处理Content-Type和数据转换 service.interceptors.request.use( function(config) { let data = config.data let ret = ""; for (let it in data) { ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&"; } config.data = ret return config; }, function(error) { return Promise.reject(error); } );
最后,给文件上传的请求单独封装一个请求即可:
export default { async post(url, data, params) { //通用的接口请求封装 ...... }, async upload(url, formData) { //文件上传专用的接口请求封装 try { formData.append('app_id', app_id); formData.append('platform', 'WX'); formData.append('resp_type', 'json'); const baseURL = (process.env.NODE_ENV === "production" ? SaasUrl : process.env.VUE_APP_BASE_API) + '/shop/base/serv'; const res = await axios.post(baseURL + url, formData); let { status, data } = res if (status == 200) { let { ret_code, ret_msg } = data if (ret_code == 0) { return data.data } else { Toast(ret_msg) return } } else { Toast('上传失败') return } } catch (err) { Toast('上传失败') console.error('上传错误:', err.response?.data || err.message) } } };
当然,如果还想细化,可以单独给上传文件再创建一个axios示例,进行更详细的请求响应处理,这里就不再说了。
页面调用上传接口:
<script> import http from '@/assets/js/api/request' export default { ...... methods:{ /** * @param {Object} file * 提交表单时上传图片 */ async afterRead(file) { let formData = new FormData(); formData.append('file', file); formData.append('img_type', 'wo_img'); let timeStamp = new Date().getTime() formData.append('filename', timeStamp + '.png'); const data = await http.upload('/upload_img', formData) return data } }
}
}
建议后端提供接口的时候提供原生js的示例demo,也可以直接使用前端的请求方式编写demo,这样前端对接接口也会快些,遇到问题也好排查。
前端遇到问题,建议先跳出框架进行单个功能调试,如果框架外正常,框架内失败,那八成是框架封装的问题了。
浙公网安备 33010602011771号