摘要

记录一个今天遇到的问题:使用 axio 上传文件过程中,传入 formData 数据,然后提示 the request was rejected because no multipart boundary was found。首先,确定这个接口是可以使用的。

如何使用 Axios 上传文件

首先需要设置 Axios 的 headers 里面的Content-Typemultipart/form-data;charset=utf-8。然后就是传入的数据必须为 FormData 数据类型。这样完成了一个初步的上传文件设置。

// import axios from "axios";
import { baseConfig, debugUser } from "../config/api.config";
import config from "../config/host.config";
import utils from "../js/utils";
import { Toast } from "vant";

// 请求发出前
axios.interceptors.request.use(async (config) => {
  // 上传文件

  if (
    config.data &&
    Object.prototype.toString.call(config.data) == "[object FormData]"
  ) {
    config.headers["Content-Type"] = "multipart/form-data;charset=utf-8";
    config.transformRequest = [
      function (data) {
        return data;
      },
    ];
  }

  if (config.params && typeof config.params != "string")
    config.params = utils.filterNull(config.params);
  if (process.env.NODE_ENV !== "production") {
    //如果是开发环境
    for (const key in debugUser) config.headers[key] = debugUser[key];
  }
  if (typeof bsch != "undefined") {
    let autho = () => {
      return new Promise((resolve, reject) => {
        bsch.autho((resp) => {
          resolve(resp);
        });
      });
    };
    let resp = await autho();
    config.headers["schoolId"] = resp.schoolId;
    config.headers["roleId"] = resp.roleId;
    config.headers["userId"] = resp.userId;
  }

  return config;
});

// http response 拦截器
axios.interceptors.response.use(
  (response) => {
    let { data, status } = response;
    return handeCallback(data, status);
  },
  function axiosRetryInterceptor(err) {
    console.log(err.message);
    console.log(err.message.indexOf("exceeded"));
    if (err.message.indexOf("exceeded") > -1) Toast.fail("网络超时!");
  }
);

const createApi = (url, params = null, method = "GET") => {
  method = method.toLocaleUpperCase();
  if (params == null) params = {};
  const baseConfigCopy = {
    ...baseConfig,
    url,
    method,
    data: method === "POST" || method === "PUT" ? params : null,
    params: method === "GET" || method === "DELETE" ? params : null,
  };

  try {
    return axios(baseConfigCopy);
  } catch (error) {
    console.error("error:" + error);
    return new Promise((reject) => reject(error));
  }
};

function createURL(url, param) {
  var paramStr = "";
  for (let key in param) {
    if (param.hasOwnProperty(key)) {
      const element = param[key];
      var link = "&" + key + "=" + element;
      paramStr += link;
    }
  }
  url = url + "?" + paramStr.substr(1);
  url = encodeURI(url);
  return url.replace(" ", "");
}

function handeCallback(resp, resCode) {
  var respStr = resp;
  if (typeof respStr === "string") {
    respStr = respStr.replace(/(\r\n)|(\n)|(\r)/g, "<br>");
    respStr = respStr.replace(/(\t)/g, "    ");
    respStr = respStr.replace(/☊/g, "'");
    respStr = respStr.replace(/♤/g, "\\");
    respStr = respStr.replace(/♢/g, "/");
    respStr = respStr.replace(/♧/g, '"');
    try {
      resp = JSON.parse(respStr);
    } catch (error) {
      alert("网络连接错误");
    }
  }

  if (resCode == 200) {
    if (resp.State || resp.code === 0) {
      return resp.data;
    } else {
      throw resp.msg;
    }
  } else {
    console.error(resCode, resp);
    throw typeof resp;
  }
}

export { createApi };

如果你设置了 header 头部的信息,然后用了 formData 数据。在接口调用的时候提示了 the request was rejected because no multipart boundary was found这个错误。

原因

某些情况下,浏览器不会给你的 Content-Type 上加上 boundary,那么就会提示这个错误。造成这个错误的原因也还有 formData 数据经过 post 之后被序列化了,所以在请求接口之前的拦截中加入如下代码

config.transformRequest = [
  function (data) {
    return data;
  },
];

官方文档中对transformRequest的解释如下
transformRequest 允许在向服务器发送前,修改请求数据只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream