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结果进行压缩

相关推荐
Bruce_Liuxiaowei12 分钟前
构建macOS命令速查手册:基于Flask的轻量级Web应用实践
前端·macos·flask
Python私教36 分钟前
安装electron项目是为什么要执行postinstall script
前端·javascript·electron
shmily_yyA1 小时前
Nextjs15 实战 - React Notes之SidebarNoteList优化和Suspense的使用
前端·react.js·前端框架
知识分享小能手1 小时前
CSS3学习教程,从入门到精通, 化妆品网站 HTML5 + CSS3 完整项目(26)
前端·javascript·css·学习·css3·html5·媒体
了不起的码农1 小时前
ES6对函数参数的新设计
前端·ecmascript·es6
XH2762 小时前
Android 通知用法详解
前端
陈随易2 小时前
盘点23个Nodejs的替代品Bun的实用功能
前端·后端·程序员
uhakadotcom2 小时前
兄弟们,炸裂了!llama 4发布了!又有哪些创业公司被颠覆了?
前端·算法·面试
uhakadotcom2 小时前
EventEmitter3:高性能事件发射器的使用与优势
前端·javascript·面试
XH2762 小时前
Android Bitmap.createBitmap() 用法全解析
前端·设计