axios对于请求体处理

151 阅读1分钟

问题描述

最近遇到问题,axios会在加密后的请求体加上双引号,导致后端解码失败。

image.png

问题排查

经过一番摸索,找到了axios处理body内容的逻辑:

// data即axios.data,请求体数据,headers为请求头信息
transformRequest: [function transformRequest(data, headers) {
    const contentType = headers.getContentType() || '';
    const hasJSONContentType = contentType.indexOf('application/json') > -1;
    const isObjectPayload = utils.isObject(data);

    if (isObjectPayload && utils.isHTMLForm(data)) {
      data = new FormData(data);
    }

    const isFormData = utils.isFormData(data);

    if (isFormData) {
      return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data;
    }

    if (utils.isArrayBuffer(data) ||
      utils.isBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data) ||
      utils.isReadableStream(data)
    ) {
      return data;
    }
    if (utils.isArrayBufferView(data)) {
      return data.buffer;
    }
    if (utils.isURLSearchParams(data)) {
      headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false);
      return data.toString();
    }

    let isFileList;

    if (isObjectPayload) {
      if (contentType.indexOf('application/x-www-form-urlencoded') > -1) {
        return toURLEncodedForm(data, this.formSerializer).toString();
      }

      if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) {
        const _FormData = this.env && this.env.FormData;

        return toFormData(
          isFileList ? {'files[]': data} : data,
          _FormData && new _FormData(),
          this.formSerializer
        );
      }
    }

    // 注意这里就是处理json数据的逻辑,只要请求头携带'application/json',或者data是个对象,就会对data进行JSON.stringfy操作
    if (isObjectPayload || hasJSONContentType ) {
      headers.setContentType('application/json', false);
      return stringifySafely(data);
    }

    return data;
  }

注意这段代码:

image.png

body内容的双引号就是这么来的

image.png

解决方案

知道了问题就很好解决了

  1. 可以考虑将请求头中的content-type改成其他类型,就不再会被axios字符串化。但是这样需要调整后端逻辑,遂没有使用该方法

  2. 最终增加了axios的处理逻辑,必须满足body不是string,并且content-typeapplication/json才进行字符串化

const request = axios.create({
    transformRequest: function transformRequest(data: any, headers: any) {
        const hasJSONContentType = () => {
            const contentType = (headers && headers["Content-Type"]) || "";
            return contentType.indexOf("application/json") > -1;
        };
        if (typeof data === "string" && hasJSONContentType()) {
            return data;
        }
        return (axios.defaults.transformRequest as any)?.[0](data, headers);
    }
});