背景:
最近项目碰到Axios提交带日期提交数据时,到后端被转成UTC时间,导致跟北京时间有8小时的差异,网上各种搜索以后,发现都不能真正的解决问题。后来进一步查询各方资料,终于真正的解决了问题。
解决过程:
网上比较多采用对Date的原型进行处理,原因是认为Axios进行提交数据时,会采用调用toISOString函数进行序列化,然后提交。实际上我在项目采用该方式处理,并不生效,具体没有很详细的去了解原因,估计是这个函数并不是必然调用的原因导致,从另外一个角度说,调整toISOString也是不合适的,有可能会产生其他坑。
Date.prototype.toISOString = function () { //author: jAmEs_
return this.Format("yyyy-MM-dd hh:mm:ss.S")
}
后来看到几个跟这个问题息息相关的信息:
https://github.com/axios/axios/issues/4380
https://github.com/axios/axios/issues/1548
解决步骤:
1. 通过原型为Date类增加两个函数(为了序列化时格式化方便使用):
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
Date.prototype.toLocalString = function () { //author: jAmEs_
return this.Format("yyyy-MM-dd hh:mm:ss.S")
}
2. 为Axios拦截增加配置:
//HTTPrequest拦截
axios.interceptors.request.use(config => {
//其他代码
//关键的代码
config.paramsSerializer = (params) => qs.stringify(params, {
serializeDate: (date) => {
console.log("serializeDate");
return date.toLocalString();
}
});
const dateTransformer = data => {
if (data instanceof Date) {
// do your specific formatting here
return data.toLocalString()
}
if (Array.isArray(data)) {
return data.map(val => dateTransformer(val))
}
if (typeof data === "object" && data !== null) {
return Object.fromEntries(Object.entries(data).map(([key, val]) =>
[key, dateTransformer(val)]))
}
return data
}
config.transformRequest = [dateTransformer].concat(axios.defaults.transformRequest)
//关键的代码
return config
}, error => {
return Promise.reject(error)
});
思路总结:
实际上,config.paramsSerializer、config.transformRequest是两个Axios请求可配置的项,可以对提交的参数进行自定义处理,其中paramsSerializer是序列化QueryString部分的,transformRequest是序列化Body部分的。