在 Axios 中自定义日期序列化
Customizing Date Serialization in Axios
默认情况下,当 JavaScript 对象包含 Date 对象时,Axios 将其序列化为 UTC。这意味着传输的时间是使用时区转换的。这不适用于我的用例。我需要将不带时区转换的时间发送为 UTC。
我实现了一个基于#1548的自定义序列化器,但是没有效果。我已验证配置正在修改,但当我查看请求负载时,日期仍在使用 UTC (2022-02-03T04:59:00.000Z)。
注意:我的逻辑比较复杂,我在下面的代码中使用了 toLocalString() 来简化示例。
const a = axios.create()
a.interceptors.request.use((config) => {
config.paramsSerializer = (params) =>
qs.stringify(params, {
serializeDate: (date: Date) => date.toLocaleString(),
})
return config
})
有人明白为什么我不能覆盖默认行为并使用我自己的日期格式吗?
环境
Axios 版本 0.21.1
序列化不是 Axios。 Date
实施 toJSON() which is employed when your objects (containing dates) are serialised via JSON.stringify()...
The instances of Date
implement the toJSON()
function by returning a string (the same as date.toISOString()
). Thus, they are treated as strings.
paramSerializer
用于序列化 query 参数,这就是它不适用于您的请求正文的原因。
要转换请求正文,您要使用 transformRequest
。
这是一个通用的递归转换器,可以查找日期并将它们映射到本地化字符串
import axios, { AxiosRequestTransformer } from "axios"
const dateTransformer: AxiosRequestTransformer = data => {
if (data instanceof Date) {
// do your specific formatting here
return data.toLocaleString()
}
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
}
然后您可以在 Axios 实例中注册此转换器,它将应用于所有 PUT、POST、PATCH 和 DELETE 请求。
const instance = axios.create({
transformRequest: [ dateTransformer ].concat(axios.defaults.transformRequest)
})
instance.post(url, data)
如果通用版本看起来有点笨拙,您可以在发布之前自行转换对象...
const body = {
date: new Date()
}
axios.post(url, {
...body,
date: body.date.toLocaleString()
})
或注册一个在线变压器
axios.post(url, body, {
transformRequest: [
data => ({
...data,
date: data.date.toLocaleString()
}),
...axios.defaults.transformRequest
]
})
这是 Phil 对 typescript 稍作修改的最优秀答案。这是针对 axios 0.21.1 的。 (在版本 0.23.1+ 中,AxiosTransformer
似乎被重构为 AxiosRequestTransformer
)
const dateTransformer = (data: any): any => {
if (data instanceof Date) {
// do your specific formatting here
return data.toLocaleString()
}
if (Array.isArray(data)) {
return data.map(dateTransformer)
}
if (typeof data === 'object' && data !== null) {
return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, dateTransformer(value)]))
}
return data
}
const axiosInstance = axios.create({
transformRequest: [dateTransformer, ...(axios.defaults.transformRequest as AxiosTransformer[])],
})
默认情况下,当 JavaScript 对象包含 Date 对象时,Axios 将其序列化为 UTC。这意味着传输的时间是使用时区转换的。这不适用于我的用例。我需要将不带时区转换的时间发送为 UTC。
我实现了一个基于#1548的自定义序列化器,但是没有效果。我已验证配置正在修改,但当我查看请求负载时,日期仍在使用 UTC (2022-02-03T04:59:00.000Z)。
注意:我的逻辑比较复杂,我在下面的代码中使用了 toLocalString() 来简化示例。
const a = axios.create()
a.interceptors.request.use((config) => {
config.paramsSerializer = (params) =>
qs.stringify(params, {
serializeDate: (date: Date) => date.toLocaleString(),
})
return config
})
有人明白为什么我不能覆盖默认行为并使用我自己的日期格式吗?
环境 Axios 版本 0.21.1
序列化不是 Axios。 Date
实施 toJSON() which is employed when your objects (containing dates) are serialised via JSON.stringify()...
The instances of
Date
implement thetoJSON()
function by returning a string (the same asdate.toISOString()
). Thus, they are treated as strings.
paramSerializer
用于序列化 query 参数,这就是它不适用于您的请求正文的原因。
要转换请求正文,您要使用 transformRequest
。
这是一个通用的递归转换器,可以查找日期并将它们映射到本地化字符串
import axios, { AxiosRequestTransformer } from "axios"
const dateTransformer: AxiosRequestTransformer = data => {
if (data instanceof Date) {
// do your specific formatting here
return data.toLocaleString()
}
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
}
然后您可以在 Axios 实例中注册此转换器,它将应用于所有 PUT、POST、PATCH 和 DELETE 请求。
const instance = axios.create({
transformRequest: [ dateTransformer ].concat(axios.defaults.transformRequest)
})
instance.post(url, data)
如果通用版本看起来有点笨拙,您可以在发布之前自行转换对象...
const body = {
date: new Date()
}
axios.post(url, {
...body,
date: body.date.toLocaleString()
})
或注册一个在线变压器
axios.post(url, body, {
transformRequest: [
data => ({
...data,
date: data.date.toLocaleString()
}),
...axios.defaults.transformRequest
]
})
这是 Phil 对 typescript 稍作修改的最优秀答案。这是针对 axios 0.21.1 的。 (在版本 0.23.1+ 中,AxiosTransformer
似乎被重构为 AxiosRequestTransformer
)
const dateTransformer = (data: any): any => {
if (data instanceof Date) {
// do your specific formatting here
return data.toLocaleString()
}
if (Array.isArray(data)) {
return data.map(dateTransformer)
}
if (typeof data === 'object' && data !== null) {
return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, dateTransformer(value)]))
}
return data
}
const axiosInstance = axios.create({
transformRequest: [dateTransformer, ...(axios.defaults.transformRequest as AxiosTransformer[])],
})