👉 个人博客主页 👈
📝 一个努力学习的程序猿


其他前端组件使用和踩坑记录文章,欢迎您查看:


先叙述一下开发需求:

有一个入参类型是 Form-Data 的接口,在其他的页面功能点上,配置了一个入参的示例,并入库保存。而在当前的需求中,进入当前这个需求的页面功能点上时,先通过其他接口拿到这个入参示例,然后将它拼装成 Form-Data 类型入参,最后传递给这个支持 Form-Data 类型的接口,成功调用即完成。而在满足以上流程后,还要支持手动上传文件,然后再拼接入参调用接口。

总结一下,即 本文要解决的问题及踩到的坑就是:

(1)如何在前端组装一个 Form-Data 类型入参成功将参数传递给接口(在这个过程中要解决: 415 状态码问题);

(2)因为在本需求中,入参示例其实是已经配置好的,在前端拿到时,其中的文件类型只能也肯定是一个存放在主机指定位置上的路径。因此第二个问题就是:如何将一个文件路径转换成 File 文件对象传递给接口(除此以外,也使用 el-upload 支持手动上传文件,并在文件上传成功后,拼接入参调用接口)。

具体内容将在下文说明。

(在具体说明所有问题前,需要额外说明的是:请先确保各位的接口在使用其他工具调用时,是 100% 能调通的。比如笔者先在 Postman 上进行了测试,发现接口正常,所以就证明文中遇到的所有问题,都是在前端发生的)



415 状态码问题 及 组装 Form-Data 类型入参

因为是初次接触 在前端组装 Form-Data 类型的入参,所以必不可少的就是在网上查阅资料。但是在网上找到了一些方法后,结果报错,状态码为 415。

在这里插入图片描述

通过查阅发现,415 的问题原因是,请求头 header 的 Content-Type 和调用接口传递的入参出现了差异,比如入参是 Form-Data 类型,但是 Content-Type 却是 application/json。

因此,对该问题的解决方案 先看简要代码:

  const params = new FormData();

  // 做数据处理
  for (let i = 0; i < this.params.length; i++) {
    params.append(this.params[i].key, this.params[i].value);
  }

  // 调用接口
  check(params).then(res => {
    // 其他操作
  });
export const check = (query) => {
  return request({
    url: 'xxx',
    method: 'post',
    data: query
  })
}

总结一下就是:像上面代码一样,使用 new FormData() 创建 FormData 对象,然后用 append 添加参数。而调用的接口,比如在这里的 check 就和普通的接口一样,不需要做特殊处理


需要特殊说明的,踩到的坑 是:

(1)在碰到 415 的时候,很多网上的文章都说要在接口上手动添加 headers。但笔者测试发现,这样做是行不通的,最后依然会是 415 或者其他奇奇怪怪的问题。如果传递的入参是 JSON 类型还说的过去,但是如果是 Form-Data 类型,且需要上传文件的时候,后面会自动生成一串 boundary,这是手动添加 headers 做不到的。

在这里插入图片描述

而实际上,我们根本不需要手动添加 headers,因为 axios 会自动处理设置Content-Type ,不需要手动设置。


(2)因为在这里要传递 Form-Data 类型入参,而很多网上的文章都说要使用 Qs 库。但通过测试发现,这样使用依然会是失败的,不是 415 就是接口提示入参错误。先展示一下使用 Qs 库的效果:

console.log(Qs.stringify({
  name: 'test',
  url: 'csdn'
}));

在这里插入图片描述

当然不排除这样可以成功传递 Form-Data 类型入参的可能性,但既然可以直接使用 new FormData() 操作,那就肯定不需要再额外引入其他库。


而通过以上的用法,显然还没有实现需求。因为在这里还没涉及到上传文件及对文件处理的用法。接下来就是如何将得到的文件地址调整成 File 对象传递给接口。


将文件的主机地址调整成 File 对象

因为在之前的需求中已经提到了,笔者在这里需要考虑将一个存储在主机上指定位置的文件路径,转换成一个 File 对象传递。否则只传递路径肯定会是入参异常的 500 状态码。

而最后找到的解决方法,它的参考到的文章如下:

https://blog.csdn.net/waxuanwa/article/details/125624577

虽然上面原文章中的用法 针对于处理图片,但去掉针对图片的动作即可(传入文件的 url 地址和文件名称):

getFileFromUrl(url, fileName) {
  return new Promise((resolve, reject) => {
    let blob = null;
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'blob';
    // 加载时处理
    xhr.onload = () => {
      // 获取返回结果
      blob = xhr.response;
      const file = new File([blob], fileName);
      // 返回结果
      resolve(file);
    };
    xhr.onerror = (e) => {
      reject(e)
    };
    // 发送
    xhr.send();
  });
}

最后返回的 File 对象就是这样的效果(和 el-upload 的效果一致,el-upload 的用法在下文说明):

在这里插入图片描述

剩下的就是把它拼装进入参,使用 FormData 对象,再将其 append 加入即可(参考上文第一部分,拼装 Form-Data 入参)。


el-upload 上传的文件,用于 Form-Data 类型入参

通过上文已经实现:拼装 Form-Data 类型的入参,在其中如果碰到的文件是一个文件路径,那就将它转换成 File 对象。而如果要手动上传文件,再拼装 Form-Data 类型入参,就可以使用 ElementUI 的 el-upload 组件。

相关 el-upload 的详细使用可以参照我之前的总结文章:

https://blog.csdn.net/qq_45613931/article/details/125258861

在这里简单贴一下核心代码(不能直接使用,请自行调整测试):

<template>
  <div>
      <el-upload
        :on-remove="handleRemove"
        :on-error="handleError"
        action="#"
        :limit="1"
        :file-list="showList"
        :http-request="httpRequest"
      >
        <el-button size="small" type="primary">
          点击上传
        </el-button>
      </el-upload>
  </div>
</template>

<script>
export default {
  data() {
    return {
      showList: []
    };
  },
  methods: {
    // 上传失败
    handleError(error) {
      this.$message.error('文件上传失败!' + error.message);
    },
    // 上传文件具体调用
    httpRequest(content) {
      this.$message.success('文件上传成功');
      console.log(content.file);
    },
    // 5.5 移除文件内容
    handleRemove() {
      this.showList = [];
    }
  }
};
</script>

总结来说,只要上传成功,那么在 httpRequest 的输出结果中,就可以直接拿到 File 对象,不需要做任何额外操作。之后只需要 append 进 FormData 对象即可:

在这里插入图片描述

在这里插入图片描述

Logo

前往低代码交流专区

更多推荐