【问题标题】:Customizing Date Serialization in Axios在 Axios 中自定义日期序列化
【发布时间】:2022-01-12 22:39:59
【问题描述】:

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

【问题讨论】:

  • 如果您需要用户时区信息,我发现最好将日期(即时)作为时间戳或 ISO 8601 UTC 日期字符串以及用户时区发送,例如 { date: "2022-01-12T00:00:00.000Z", tz: "America/New_York" }
  • 是的,但这不是问题。
  • 这就是为什么它是评论而不是答案

标签: javascript typescript axios interceptor utc


【解决方案1】:

不是 Axios 做序列化。 Date 实现 toJSON() 当您的对象(包含日期)通过 JSON.stringify() 序列化时使用...

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

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
  ]
})

【讨论】:

  • 非常有帮助。感谢您花时间详细回答。
【解决方案2】:

这是 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[])],
})

【讨论】:

  • 仅供参考,如果您使用 typescript 标记您的问题,您将收到 Typescript 答案
  • 有道理。我没有抱怨。你的回答太棒了,但我会记住这一点以供将来参考。
猜你喜欢
  • 2016-11-11
  • 2015-01-30
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多