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

相关推荐
^小桃冰茶1 小时前
HTML 从标签到动态效果的基础
前端·html
火柴盒zhang1 小时前
基于HTML CANVAS和EXCEL的xlsx文件展示工具websheet
前端·javascript·html·spreadsheet·websheet
一城烟雨_5 小时前
vue3 实现将html内容导出为图片、pdf和word
前端·javascript·vue.js·pdf
树懒的梦想6 小时前
调整vscode的插件安装位置
前端·cursor
低代码布道师7 小时前
第二部分:网页的妆容 —— CSS(下)
前端·css
一纸忘忧7 小时前
成立一周年!开源的本土化中文文档知识库
前端·javascript·github
涵信8 小时前
第九节:性能优化高频题-首屏加载优化策略
前端·vue.js·性能优化
前端小巷子8 小时前
CSS单位完全指南
前端·css
艾小逗9 小时前
uniapp中检查版本,提示升级app,安卓下载apk,ios跳转应用商店
android·ios·uni-app·app升级
SunTecTec9 小时前
Flink Docker Application Mode 命令解析 - 修改命令以启用 Web UI
大数据·前端·docker·flink