在 Axios 中自定义日期序列化

问题描述 投票:0回答:3

默认情况下,当 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

javascript typescript axios interceptor utc
3个回答
27
投票

序列化不是 Axios 进行的。

Date
实现 toJSON() 当您的对象(包含日期)通过 JSON.stringify()...

序列化时使用它

Date
的实例通过返回字符串来实现
toJSON()
函数(与
date.toISOString()
相同)。因此,它们被视为字符串。

paramSerializer
用于序列化query参数,这就是它不适用于您的请求正文的原因。

要转换请求正文,您需要使用

transformRequest

这是一个通用的递归转换器,可以查找日期并将其映射到本地化字符串

import axios, { AxiosRequestTransformer } from 'axios';

const isPlainObject = (v: unknown) =>
  Object.prototype.toString.call(v) === '[object Object]';

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 (isPlainObject(data)) {
    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
  ]
})

6
投票

这是菲尔最优秀的答案,对打字稿进行了小修改。这是针对 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[])],
})

-1
投票
    const replacer = function(this: any, key: string, value: any) {
        if (this[key] instanceof Date) {
           return moment(this[key]).format("YYYY-MM-DD HH:mm:ss")
        }    
        return value
    }
    
    const axiosInstance = axios.create({
      transformRequest: [(data, headers) => JSON.stringify(data, replacer), ...(axios.defaults.transformRequest as AxiosRequestTransformer[])]
    })
© www.soinside.com 2019 - 2024. All rights reserved.