【问题标题】:Axios interceptor to retry sending FormDataaxios拦截器重试发送FormData
【发布时间】:2021-01-22 12:37:05
【问题描述】:

我正在尝试为包含FormData 作为数据的请求创建“重试”功能。 重试发生在 JWT 令牌过期时,我的第二个请求(重试)不包含任何数据。

想法:

const axiosInstance = axios.create();

  /**
   * Before each request, we'll add a possible retry if the
   * request need a refreshed token
   */
  axiosInstance.interceptors.request.use((request) => {
    if (typeof _.get(request, ['retried']) === 'undefined') {
      request.retried = false;
    }

    return request;
  });

/**
   * After a request with an error, we'll check if the error is a token not refreshed.
   * If we didn't already tried to refresh, we'll just fallback to the errorHandler function
   */
  axiosInstance.interceptors.response.use(null, async (error) => {
    const statusCode = _.get(error, ['response', 'data', 'statusCode']);
    const message = _.get(error, ['response', 'data', 'message']);
    const { config: request = {} } = error;

    if (statusCode === 401 && !request.retried) {
      try {
        const newTokens = await refreshTokens();
        request.retried = true;
        _.set(request, ['headers', 'authorization'], newTokens.accessToken);
        return axiosInstance.request(request);
      } catch (e) {
        return error;
      }
    }
    return error;
  });

请求:

  const formData = new FormData();
  formData.append('name', name);
  formData.append('file', fs.createReadStream(file.path));

  axiosInstance.post(
      'http://localhost/upload',
      formData,
      {
        headers: {
          ...formData.getHeaders(),
          authorization: tokens.accessToken
        }
      }
    );

如果我的令牌过期,请求将失败,然后拦截器将刷新我的令牌,并仅使用新标头 Authorization 重试完全相同的请求。然而,在服务器端,接收到的有效载荷始终为空。

【问题讨论】:

  • 嘿,你能在哪里解决这个问题?
  • 不幸的是,不,正如@tnarik 在下面的答案中所说,一旦 formData (它是一个流)被消耗,它就不能再次使用。您必须找到一种方法来重新创建 formData 才能将其再次添加到下一个请求中:/ 编辑:至少这就是我在这个问题上的进展。也许有人对此有更好的解决方案!
  • 另一种使用拦截器的解决方案是创建一个端点来检查您的令牌(仅此而已),如果拦截的请求具有 formData,则在 interceptors.request.use 钩子中发送请求。在某种程度上你会说“如果这个请求有一个 formData,让我 ping 我的后端并检查我的令牌是否正确,如果不正确,则刷新并继续”。
  • 这就是我所做的,我在发送之前检查是否过期,如果是这种情况,我会重新获取令牌。仅适用于 formData 请求。谢谢!
  • 不客气。不要犹豫,用stackoverflow上的代码创建你自己的问题和响应,它可能会在某个时候帮助别人! ;)

标签: javascript axios interceptor


【解决方案1】:

据我所知,重试时需要再次添加formData(我认为是由于数据被添加为流并在请求期间消费,因此新的重试无法消费已经消费的流) .

您可以查看request.data 了解我的意思。

【讨论】:

    【解决方案2】:

    您可以在配置参数中传递表单数据:

    axiosInstance.post(
      'http://localhost/upload',
      {},
      {
        data: formData, // <---- pass it here
        headers: {
          ...formData.getHeaders(),
          authorization: tokens.accessToken
        }
      }
    );
    

    【讨论】:

    • 您能详细说明一下吗?我尝试了您的想法,但无法实现,因为它将表单作为数据发送到服务器并弄乱了一切
    猜你喜欢
    • 2020-11-21
    • 2017-08-22
    • 2021-08-06
    • 2020-02-12
    • 2021-05-04
    • 2018-11-27
    • 2022-11-09
    • 2019-06-26
    • 2022-11-14
    相关资源
    最近更新 更多