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,这样前端对接接口也会快些,遇到问题也好排查。

前端遇到问题,建议先跳出框架进行单个功能调试,如果框架外正常,框架内失败,那八成是框架封装的问题了。

posted on 2025-05-21 11:53  逍遥云天  阅读(60)  评论(0)    收藏  举报

导航