Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

读 axios 源码实现自动重发请求 #82

Open
akaxiaok opened this issue Apr 22, 2020 · 1 comment
Open

读 axios 源码实现自动重发请求 #82

akaxiaok opened this issue Apr 22, 2020 · 1 comment

Comments

@akaxiaok
Copy link
Owner

akaxiaok commented Apr 22, 2020

Axios.prototype.request = function request(config) {

  // 一些配置代码
  /*eslint no-param-reassign:0*/
  // Allow for axios('example/url'[, config]) a la fetch API
  if (typeof config === 'string') {
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }

  config = mergeConfig(this.defaults, config);


  // chain 数组包含发送一个请求需要依次执行的方法,而 dispatchRequest 为实际发送请求的方法,
  // 因此在 dispatchRequest 之前的为 request interceptors,之后的为 response interceptors
  // Hook up interceptors middleware
  var chain = [dispatchRequest, undefined];

  // 处理链始于此
  var promise = Promise.resolve(config);

  // use 的每一个 interceptor,会保存在内部数组,在此遍历该数组
  // 把成功回调 interceptor.fulfilled 函数和失败回调 interceptor.rejected 函数加入 chain
  // 回想一下 use 的方法签名 axios.interceptors.use(fulfilled,rejected)
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  // 同上
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

  while (chain.length) {
    // 开始注册处理链,每当上一个 interceptor 处理完后,交个下一个 interceptor。中间包含一个 dispatchRequest 实际发送请求
    promise = promise.then(chain.shift(), chain.shift());
  }

  // 返回最后的 promise
  // 回想一下请求方法签名 axios.request(config).then(handler).catch(handler)
  // 执行顺序为,request interceptors -> dispatchRequest 实际请求 -> response interceptors -> 自己的处理 handler
  // 我们要刷新 token 在重发请求,则可以在一个 response interceptor 里处理,因为只要这个 interceptor 没有 fulfilled,那么原请求的自定义 handler 就不会执行
  return promise;
};
@akaxiaok akaxiaok changed the title axios token 过期时刷新 token 自动重发原请求 读 axios 源码实现自动重发请求 Apr 22, 2020
@akaxiaok
Copy link
Owner Author

akaxiaok commented Apr 23, 2020

axios-auth-refresh 的实现

export default function createAuthRefreshInterceptor(
    instance: AxiosInstance,
    refreshAuthCall: (error: any) => Promise<any>,
    options: AxiosAuthRefreshOptions = {},
): number {
    if (typeof refreshAuthCall !== 'function') {
        throw new Error('axios-auth-refresh requires `refreshAuthCall` to be a function that returns a promise.');
    }
    // 注册一个 response interceptor
    return instance.interceptors.response.use((response: AxiosResponse) => response, (error: any) => {

        options = mergeOptions(defaultOptions, options);

        // 判断是否跳过该 interceptor
        if (!shouldInterceptError(error, options, instance, cache)) {
            return Promise.reject(error);
        }

        //
        cache.skipInstances.push(instance);

        // If refresh call does not exist, create one
        // 调用刷新函数 refreshAuthCall,如果多个请求失败,已经有刷新在执行,则不再调用
        const refreshing = createRefreshCall(error, refreshAuthCall, cache);

        // Create interceptor that will bind all the others requests until refreshAuthCall is resolved
        // 重发请求之前添加一个 request interceptor,运行自定义的 onRetry
        createRequestQueueInterceptor(instance, cache, options);

        return refreshing
            .finally(() => unsetCache(instance, cache))
            .catch(error => Promise.reject(error))
            // 刷新完成后,重新发送原请求
            .then(() => resendFailedRequest(error, getRetryInstance(instance, options)));
    });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant