javascript - Tilpasse datoserialisering i Axios


Som standard, når et JavaScript-objekt inneholder et Date-objekt, serialiserer Axios det til UTC. Dette betyr at tiden som sendes, konverteres ved bruk av tidssonen. Dette fungerer ikke for mitt brukstilfelle. Jeg må sende tiden uten tidssonenkonvertering til UTC.

Jeg implementerte en tilpasset serialiserer basert på #1548, men den har ingen effekt. Jeg har bekreftet at konfigurasjonen blir endret, men når jeg ser på forespørselsinnholdet, bruker datoene fortsatt UTC (2022-02-03T04:59:00.000Z).

Merk: Min logikk er mer komplisert, jeg bruker toLocalString() i koden nedenfor for å forenkle eksemplet.

const a = axios.create()
a.interceptors.request.use((config) => {
  config.paramsSerializer = (params) =>
    qs.stringify(params, {
      serializeDate: (date: Date) => date.toLocaleString(),
    })
  return config
})

Forstår noen hvorfor jeg ikke kan overstyre standardoppførselen og bruke mitt eget datoformat?

Miljø Axios Versjon 0.21.1

Svar #1

Det er ikke Axios som gjør serialiseringen. Date implementerer toJSON(), som brukes når objektene dine (som inneholder datoer) serialiseres via JSON.stringify()...

Forekomstene av Date implementerer toJSON()-funksjonen ved å returnere en streng (den samme som date.toISOString()). Dermed behandles de som strenger.

paramSerializer er for å serialisere spørrings-parametere, og derfor ble det ikke brukt på forespørselskroppen din.

For å transformere forespørselens innhold, vil du bruke transformRequest.

Her er en generell, rekursiv transformator som finner datoer og mapper dem til lokaliserte strenger

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;
};

Du kan deretter registrere denne transformatoren i din Axios-instans, som vil gjelde for alle PUT-, POST-, PATCH- og DELETE-forespørsler.

const instance = axios.create({
  transformRequest: [ dateTransformer ].concat(axios.defaults.transformRequest)
})

instance.post(url, data)

Hvis den generiske versjonen virker litt påtrengende, kan du enten omforme objektet selv før du legger det ut...

const body = {
  date: new Date()
}

axios.post(url, {
  ...body,
  date: body.date.toLocaleString()
})

eller registrer en inline-transformator

axios.post(url, body, {
  transformRequest: [
    data => ({
      ...data,
      date: data.date.toLocaleString()
    }),
    ...axios.defaults.transformRequest
  ]
})

Svar #2

Dette er Phils mest utmerkede svar med små endringer for TypeScript. Dette er for axios 0.21.1. (I versjon 0.23.1+ ser det ut til at AxiosTransformer ble refaktorert til 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[])],
})

Relaterte artikler