Axios:如何正确取消请求拦截器内的请求?

时间:2018-05-22 07:08:49

标签: javascript axios

如果没有令牌,我想取消请求,所以我喜欢这样:

instance.interceptors.request.use(config => {
  if (!getToken()) {
    console.log("interceptors: no access token");
  } else {
    config.headers.Authorization = "Bearer " + getToken().accessToken;
    return config;
  }
});

但在负面情况下,出现错误TypeError: Cannot read property 'cancelToken' of undefined

6 个答案:

答案 0 :(得分:2)

对于后来的谷歌人来说,这是一个很好的解决方案,取自 axios issue on github

instance.interceptors.request.use(config => {
  /* some logic */
  return {
    ...config,
    cancelToken: new CancelToken((cancel) => cancel('Cancel repeated request'))
  };
});

这几乎是 Vijay 提出的,但形式更简洁。

答案 1 :(得分:1)

您不能在拦截器内使用令牌,而是抛出Cancel

axios.interceptors.response.use(function (response) {
  throw new axios.Cancel('Operation canceled by the user.');
}, function (error) {
  return Promise.reject(error);
});

参考这篇文章: https://github.com/axios/axios/issues/583

答案 2 :(得分:1)

@Kirill Taletski 的回答完美解决了这个问题,但添加一行:

const CancelToken = Axios.CancelToken;

然后,它会是这样的:

instance.interceptors.request.use(config => {
  /* some logic */
  const CancelToken = Axios.CancelToken;
  return {
    ...config,
    cancelToken: new CancelToken((cancel) => cancel('Cancel repeated request'))
  };
});

答案 3 :(得分:0)

这是解决方法

 <div class="year-div">
        <input type="number" [(ngModel)]="year" value="2019" min="2018" max="2024">
   </div>

答案 4 :(得分:0)

我以这种方式实现了这一点。我不确定这是否是最好的解决方案,但对于我的用例来说很有用。 我的想法是不取消最后一个请求。我想取消对同一端点的先前请求,并让最后一个执行他的工作。因此,我跟踪正在执行的请求。

// I keep track of the current requests that are being executed
const currentExecutingRequests = {};

axios.interceptors.request.use(
    (req) => {
        let originalRequest = req;

        if (currentExecutingRequests[req.url]) {
            const source = currentExecutingRequests[req.url];
            delete currentExecutingRequests[req.url];
            source.cancel();
        }

        const CancelToken = axios.CancelToken;
        const source = CancelToken.source();
        originalRequest.cancelToken = source.token;
        currentExecutingRequests[req.url] = source;

        // here you could add the authorization header to the request

        return originalRequest;
    },
    (err) => {
        return Promise.reject(err);
    }
);

axios.interceptors.response.use(
    (response) => {
        if (currentExecutingRequests[response.request.responseURL]) {
            // here you clean the request
            delete currentExecutingRequests[response.request.responseURL];
        }
        return response;
    },
    (error) => {
        const { config, response } = error;
        const originalRequest = config;

        if (axios.isCancel(error)) {
            // here you check if this is a cancelled request to drop it silently (without error)
            return new Promise(() => {});
        }

        if (currentExecutingRequests[originalRequest.url]) {
            // here you clean the request
            delete currentExecutingRequests[originalRequest.url];
        }

        // here you could check expired token and refresh it if necessary

        return Promise.reject(error);
    }
);

答案 5 :(得分:0)

我的解决方案基于 https://stackoverflow.com/a/64228288/2051938

axios.ts

const axiosInstance = axios.create({ baseURL: apiBaseUrl });

axiosInstance.interceptors.request.use(
    req => {
        const originalRequest = req;
        const cancelUniqId = (originalRequest.cancelToken as unknown) as string;

        if (Object.hasOwnProperty.call(currentExecutingRequests, cancelUniqId)) {
            const source = currentExecutingRequests[cancelUniqId];
            delete currentExecutingRequests[cancelUniqId];
            source.cancel();
        }

        if (cancelUniqId) {
            const CancelToken = axios.CancelToken;
            const source = CancelToken.source();
            originalRequest.cancelToken = source.token;
            currentExecutingRequests[cancelUniqId] = source;
        }

        return originalRequest;
    },
    err => {
        return Promise.reject(err);
    }
);

axiosInstance.interceptors.response.use(
    response => {
        for (const key of Object.keys(currentExecutingRequests)) {
            if (currentExecutingRequests[key].token === response.config.cancelToken) {
                delete currentExecutingRequests[key];
                break;
            }
        }
        return response;
    },
    error => {
        const { response } = error;

        if (axios.isCancel(error)) {
            return new Promise(() => {
                //
            });
        }

        for (const key of Object.keys(currentExecutingRequests)) {
            if (currentExecutingRequests[key].token === response.config.cancelToken) {
                delete currentExecutingRequests[key];
                break;
            }
        }

        return Promise.reject(error);
    }
);

export { axiosInstance };

用法:

axiosInstance.request({
    url: "some/req/path",
    method: "POST",
    params: {...},
    data: {...},
    cancelToken: "someUniqRequestID" // <-- IMPORTANT!
})

因此,如果之前使用 SAME someUniqRequestID 的请求尚未完成,则所有使用 cancelToken 令牌的请求都将被取消。