起因
- 表单提交的数据
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()处理。(以后碰到这种问题就可以一步一步走进去看看具体原理,就可以豁然开朗)