如何执行异步提取请求,然后重试上一个失败的请求? [英] How to execute an async fetch request and then retry last failed request?

查看:228
本文介绍了如何执行异步提取请求,然后重试上一个失败的请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Apollo链接提供了一个错误处理程序onError

问题: 目前,我们希望在opol令牌在阿波罗调用期间到期时刷新它们,并且我们无法在onError内部正确执行异步获取请求.

Issue: Currently, we wish to refresh oauth tokens when they expires during an apollo call and we are unable to execute an async fetch request inside the onError properly.

代码:

initApolloClient.js

import { ApolloClient } from 'apollo-client';
import { onError } from 'apollo-link-error';
import { ApolloLink, fromPromise } from 'apollo-link';

//Define Http link
const httpLink = new createHttpLink({
    uri: '/my-graphql-endpoint',
    credentials: 'include'
});

//Add on error handler for apollo link

return new ApolloClient({
    link: ApolloLink.from([
        onError(({ graphQLErrors, networkError, operation, forward  }) => {
            if (graphQLErrors) {
                //User access token has expired
                if(graphQLErrors[0].message==="Unauthorized") {
                    //We assume we have both tokens needed to run the async request
                    if(refreshToken && clientToken) {
                        //let's refresh token through async request
                        return fromPromise(
                            authAPI.requestRefreshToken(refreshToken,clientToken)
                            .then((refreshResponse) => {
                                let headers = {
                                    //readd old headers
                                    ...operation.getContext().headers,
                                    //switch out old access token for new one
                                    authorization: `Bearer ${refreshResponse.access_token}`,
                                };

                                operation.setContext({
                                    headers
                                });

                                //Retry last failed request
                                return forward(operation);
                            })
                            .catch(function (error) {
                                //No refresh or client token available, we force user to login
                                return error;
                            })
                        )
                    }
                }
            }
        }
    }
}),

会发生什么:

  1. 最初的graphQL查询由于未授权而运行并失败
  2. 执行ApolloLinkonError功能.
  3. 执行刷新令牌的承诺.
  4. 再次执行ApolloLinkonError功能?
  5. 刷新令牌的承诺已完成.
  6. 返回初始graphQL查询结果,其数据为undefined
  1. Initial graphQL query runs and fails due to unauthorization
  2. The onError function of ApolloLink is executed.
  3. The promise to refresh the token is executed.
  4. The onError function of ApolloLink is executed again??
  5. The promise to refresh the token is completed.
  6. The initial graphQL query result is returned and its data is undefined

在第5步和第6步之间, apollo不会重新运行最初失败的graphQL查询,因此结果为undefined.

Between step 5 and 6, apollo doesn't re-run the initial failed graphQL query and hence the result is undefined.

控制台错误:

Uncaught (in promise) Error: Network error: Error writing result to store for query:
 query UserProfile($id: ID!) {
  UserProfile(id: $id) {
    id
    email
    first_name
    last_name
    }
    __typename
  }
}

该解决方案应允许我们:

The solution should allow us to:

  1. 操作失败时运行异步请求
  2. 等待请求的结果
  3. 使用请求结果中的数据重试失败的操作
  4. 操作应成功返回其预期结果

推荐答案

我正在以这种方式刷新令牌(更新的OP):

I'm refreshing the token this way (updated OP's):

import { ApolloClient } from 'apollo-client';
import { onError } from 'apollo-link-error';
import { ApolloLink, Observable } from 'apollo-link';  // add Observable

// Define Http link
const httpLink = new createHttpLink({
  uri: '/my-graphql-endpoint',
  credentials: 'include'
});

// Add on error handler for apollo link

return new ApolloClient({
  link: ApolloLink.from([
    onError(({ graphQLErrors, networkError, operation, forward }) => {
      // User access token has expired
      if (graphQLErrors && graphQLErrors[0].message === 'Unauthorized') {
        // We assume we have both tokens needed to run the async request
        if (refreshToken && clientToken) {
          // Let's refresh token through async request
          return new Observable(observer => {
            authAPI.requestRefreshToken(refreshToken, clientToken)
              .then(refreshResponse => {
                operation.setContext(({ headers = {} }) => ({
                  headers: {
                    // Re-add old headers
                    ...headers,
                    // Switch out old access token for new one
                    authorization: `Bearer ${refreshResponse.access_token}` || null,
                  }
                }));
              })
              .then(() => {
                const subscriber = {
                  next: observer.next.bind(observer),
                  error: observer.error.bind(observer),
                  complete: observer.complete.bind(observer)
                };

                // Retry last failed request
                forward(operation).subscribe(subscriber);
              })
              .catch(error => {
                // No refresh or client token available, we force user to login
                observer.error(error);
              });
          });
        }
      }
    })
  ])
});

这篇关于如何执行异步提取请求,然后重试上一个失败的请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆