前言

最近接到一个需求,登录后需要把站点id 加入到请求header 中。那么我们很容易就能想到通过用axios 的拦截器中设置就可以了,页面打开后必定会调用一个获取站点(getStation) 的接口拿到station_id 后,给其余的所有接口header 都加上 station_id, 但问题是当打开页面的时候,页面可能会同时调用其他接口,你并不能明确知道你这个接口一定是先返回的。

思路

我们可以在没有station信息的时候将请求加入到队列中。但是这样会reject后
控制台会Promise.reject 报错,所以这种并不合适

const queue: any[] = []
/** 是否在获取station */
function initStation() {
  const STATION_URL = GetStation.url
  const BLACK_URLS = [
    Token.url,
  ]
  let stationData: GetStationResponse | null = null

  instance.interceptors.request.use((config) => {
    if (BLACK_URLS.includes(config.url!)) {
      return config
    }
    if (!stationData?.station) {
      // eslint-disable-next-line no-new
      new Promise((resolve) => {
        queue.push({
          config,
          resolve,
        })
      })
      return Promise.reject(config)
    }
    const type = stationData?.station?.type

    config.headers['x-station-id'] = stationData?.station?.station_id || '0'
    return config
  })

  instance.interceptors.response.use((response) => {
    if (response.config.url?.includes(STATION_URL)) {
      const json: GetStationResponse = response.data
      stationData = json
      queue.forEach(({ config, resolve }) => {
        config.headers['x-station-id'] = json.station.station_id || '0'
        resolve(instance(config))
      })
    }
    return response
  })
}

另一种方法

如果站点信息 没有值的时候,其他请求都在等待中,等getStation 返回后再回来执行其他请求

export function initStation() {
  const STATION_URL = GetStation.url
  const BLACK_URLS = [
    Token.url,
    STATION_URL,
  ]
  let stationData: GetStationResponse | null = null
  let tempResult: (res: GetStationResponse) => void

  const resultPromise = new Promise<GetStationResponse>((resolve) => {
    tempResult = (res: GetStationResponse) => {
      stationData = res
      resolve(res)
    }
  })

  instance.interceptors.request.use((config) => {
    if (BLACK_URLS.includes(config.url!)) {
      return config
    }
    /** 如果没拿到station 数据那么就等待 */
    if (!stationData?.station) {
      return resultPromise.then((res) => {
        config.headers['x-station-id'] = res?.station?.station_id || '0'

        return config
      })
    }

    config.headers['x-station-id'] = stationData?.station?.station_id || '0'

    return config
  })

  instance.interceptors.response.use(
    (response) => {
      /** 如果当前返回了,那么执行回调 */
      if (response.config.url?.includes(STATION_URL)) {
        const json: GetStationResponse = response.data
        tempResult(json)
      }
      return response
    },
    (error) => {
      return Promise.reject(error)
    },
  )
}

注意事项

因为接口一直在排队,可能会造成影响,比如devtool -> network 是看不到请求的