axios-post对data的默认处理

1,716 阅读2分钟

起因

  • 表单提交的数据
api.post(`xxx`, {
	brandGoodId: undefined
	categoryName: "test41"
	coverImgUrl: "hello"
	description: undefined
})

提交的数据有可能是 undefined,但是后端并未处理而且很有可能当做字符串处理而直接存入数据库,但是这很有可能并不是期望结果。

结果

经测试发现虽然我提交了上面那样的对象,但最终在network中看到的数据如下:

{
	categoryId: 5503
	categoryName: "test41"
	imgUrl: "hello"
}

很明显为undefined的属性在提交上去的数据中并没有出现对应字段(符合后端预期或者逻辑)

解决

  • 首先查看项目中现有的axios的封装,是否已经存在对他们的处理(经查验只是一些常见的配置并未对提交的数据进行处理)
  • 那么就很有可能是axios本身对其做了一层处理,排查过程如下:

Axios.js

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  console.log(data)	// 这里的 data 仍为一开始的数据
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});


Axios.prototype.request = function request(config) {
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  if (typeof config === 'string') {
    config = utils.merge({
      url: arguments[0]
    }, arguments[1]);
  }

  config = utils.merge(defaults, {method: 'get'}, this.defaults, config);
  config.method = config.method.toLowerCase();

  // Hook up interceptors middleware
  // 重点:可以看到这里有 chain 数组,进入 dispatchRequest 函数
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);

  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

  return promise;
};

dispatchRequest.js

// Transform request data
config.data = transformData(
	config.data,
	config.headers,
	config.transformRequest
);

transformData.js

module.exports = function transformData(data, headers, fns) {
  /*eslint no-param-reassign:0*/
  console.log(String(fns[0]))
  utils.forEach(fns, function transform(fn) {
    data = fn(data, headers);
  });

  return data;
};

打印的内容

function transformRequest(data, headers) {
    normalizeHeaderName(headers, 'Content-Type');
    if (utils.isFormData(data) ||
      utils.isArrayBuffer(data) ||
      utils.isBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data)
    ) {
      return data;
    }
    if (utils.isArrayBufferView(data)) {
      return data.buffer;
    }
    if (utils.isURLSearchParams(data)) {
      setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
      return data.toString();
    }
    // 重点:走到了这里,发现原来是做了一层序列化处理,正是因为 JSON.stringify(obj) 会把 undefined 的属性过滤掉
    if (utils.isObject(data)) {
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }
    return data;
}

验证一下: dispatchRequest.js

// Transform request data
config.data = transformData(
	config.data,
	config.headers,
	config.transformRequest
);
console.log(config.data);
// result: right
{
	"categoryId":5503,
	"categoryName":"test41",
	"imgUrl":"hello"
}

结论

axios会默认在请求拦截器中对data做一层JSON.stringify()处理。(以后碰到这种问题就可以一步一步走进去看看具体原理,就可以豁然开朗)