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

相关推荐
大怪v2 小时前
AI抢饭?前端佬:我要验牌!
前端·人工智能·程序员
新酱爱学习2 小时前
字节外包一年,我的技术成长之路
前端·程序员·年终总结
小兵张健2 小时前
开源 playwright-pool 会话池来了
前端·javascript·github
IT_陈寒5 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端
codingWhat5 小时前
介绍一个手势识别库——AlloyFinger
前端·javascript·vue.js
代码老中医5 小时前
2026年CSS彻底疯了:这6个新特性让我删掉了三分之一JS代码
前端
不会敲代码16 小时前
Zustand:轻量级状态管理,从入门到实践
前端·typescript
踩着两条虫6 小时前
VTJ.PRO 双向代码转换原理揭秘
前端·vue.js·人工智能
扉川川6 小时前
OpenClaw 架构解析:一个生产级 AI Agent 是如何设计的
前端·人工智能
远山枫谷6 小时前
一文理清页面/组件通信与 Store 全局状态管理
前端·微信小程序