uni-app的uni.upload上传图片报错

前言

Uniapp真是个大坑?不管你是否赞同这个观点,反正我是这么认为的。 但是,又没有开发原生的成本和精力,所以就跟鸡肋一样。 食之无味,弃之可惜。

今天我就分享一下我遇到的一个坑。

开始

项目需求,移动端上传图片,一下就想到使用uniapp自带的上传组件

这里用到的是vue3写法

vue 复制代码
 <uni-file-picker ref="images"> </uni-file-picker>

如果是多张图片的上传,遍历images内的filesList数组

javaScript 复制代码
    const sceneFileImgs = [];
    if (images.value.filesList && images.value.filesList.length > 0) {
      images.value.filesList.forEach((i, index) => {
        sceneFileImgs.push({ name: `sceneFileImgs[${index}].png`, uri: i.url });
      });
    }

按照Uniapp的文档,字段名称格式为

这里files的对象名称要根据接口来定。

他们要的字段是什么名字,你就跟他命名一致,像我这里是sceneFileImgs formData 是接口需要提交的额外参数,这里不用 再包含 sceneFileImgs

javaScript 复制代码
    uni.uploadFile({
      url:'https://juejin.cn/api/submit',
      files: sceneFileImgs,
      header: {
        Authorization: uni.getStorageSync('token'),
      },
      formData: formDatas,
      complete: res => {
        if (data.code === 0) {
          toast('提交成功');
        } else {
          toast(`${data.msg}`);
        }
      },
    });

H5上开始调试,完美!

Android上调试,完美!

但是!

IOS就会失败,接口都没有进行请求

黑人问号

网上搜了一圈,说是IOS在接口上要强制手动添加 'Content-Type': 'multipart/form-data'

但是

加上去之后发现,后端报错了

这啥问题呢?

报错提示后端在解析你的请求头时,发现在你的请求头里没有找到 boundary

boundary 就是formData数据的分隔符,

所以,正是因为你写了content-type之后,覆盖了浏览器自己帮你拼上的boundary

那怎么办?

那好,咱获取一下formDataboundary ,再拼到请求头上。

想法太天真了

因为boundary 获取不到,前端无论你在哪里都获取不到

所以陷入了死循环

那到底怎么解决呢?

只能放弃uniapp提供的upload方法

自己定义接口,使用axios或者ajax,这样IOS在请求的时候会自动 给你加上Content-Type

接下来就是见证奇迹的时候

附录

附上自定义的接口代码

JavaScript 复制代码
    const sceneFileImgs = [];
    if (images.value.filesList && images.value.filesList.length > 0) {
      images.value.filesList.forEach((i, index) => {
        sceneFileImgs.push({ name: i.name, uri: i.url });
      });
    }
    Object.keys(formDatasClone).forEach(key => {
        formData.append(key, formDatasClone[key]);
      });
    // 请求头的配置,不需要再配置 Content-Type
    // 无论是IOS还是安卓都会自动帮你添加上去
    const config = {
        headers: {
          Authorization: uni.getStorageSync('token'),
        },
    };
    for (let index = 0; index < sceneFileImgs.length; index++) {
        const el = sceneFileImgs[index];
        // 将blodUrl 转换成 File格式
        await getFileFromUrl(el.uri, el.name)
          .then(response => {
            formData.append(`sceneFileImgs[${index}]`, response);
          })
      }

      axios.post('https://juejin.cn/api/submit', formData, config).then(res => {
        if (res.data.code === 0) {
          toast('提交成功');
        } else {
          toast(`${res.data.msg}`);
        }
      })

getFileFromUrl函数

JavaScript 复制代码
  // 将blodUrl 转换成 File格式
  const getFileFromUrl = (url, fileName) => {
    return new Promise((resolve, reject) => {
      var blob = null;
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.setRequestHeader('Accept', 'image/png');
      xhr.responseType = 'blob';
      // 加载时处理
      xhr.onload = async () => {
        // 获取返回结果
        blob = xhr.response;
        let file = new File([blob], fileName, { type: 'image/png' });
        resolve(file);
      };
      xhr.onerror = e => {
        reject(e);
      };
      // 发送
      xhr.send();
    });
  };

后续

移动端上传的图片太大,我们可以进行压缩处理 在getFileFromUrl函数返回file结果进行压缩

相关推荐
用户8820932166718 分钟前
Vue组件通信全攻略:从父子传参到全局状态管理,一篇搞定!
前端
Canmick22 分钟前
JavaScript 异步函数健身操
前端·javascript
一曝十寒23 分钟前
那些常见的 HTTP 状态码
前端·http
WildBlue23 分钟前
🚀 React初体验:从“秃头程序员”到“数据魔法师”的奇幻漂流
前端·react.js
JosieBook23 分钟前
【Web应用】若依框架:基础篇14 源码阅读-后端代码分析-课程管理模块前后端代码分析
前端
前端小嘎28 分钟前
被大厂裁员后做的前端工具网站
前端
超级土豆粉28 分钟前
CSS 预处理器与工具
前端·css
Jackson__1 小时前
聊聊 JS 中的可选链 ?.
前端
前端小崔1 小时前
前端面试题之ES6保姆级教程
开发语言·前端·javascript·面试·职场和发展·ecmascript·es6
Bug从此不上门1 小时前
【无标题】
前端·javascript·uni-app·vue