Apollo Graphql при обновлении токена не обновляет запрос на использование

#reactjs #graphql #jwt #next.js #apollo

Вопрос:

Я сталкиваюсь со следующей проблемой: у меня есть крючок для получения пользовательских данных

Запрос на использование GET_USER_INFO

 const { data:dataGetUserInfo, loading:loadingQuery, error:errorQuery,refetch  } = useQuery(GET_USER_INFO, {variables: {
            getUserInfoInfoId: userId
        }});
 

И я хочу обновить доступ и обновить токены, когда срок действия токена доступа истечет. Для этого я сделал ссылку на ошибку в apollo-client.ts, которая вызывает функцию refesh, когда это необходимо, а затем возвращает мой запрос на использование GET_USER_INFO

apollo-клиент.ts

 const getNewToken =  () => {
    let refreshToken

        refreshToken = localStorage.getItem("REFRESH");

    return client.mutate({
        mutation: REFRESH_TOKEN,
        variables:{
            refreshTokenRefreshToken : refreshToken,
        }
    })
        .then((res) => {
            localStorage.clear();
            const { accessToken,refreshToken } = res.data.refreshToken;
            localStorage.setItem('REFRESH',refreshToken)
            localStorage.setItem('AUTHORIZATION',accessToken)
            return res.data;
        }).catch((err)=>{
            console.log(err)
            
        })

};



const errorLink = onError(
    ({ graphQLErrors, networkError, operation, forward }) => {
        if (graphQLErrors) {
            for (let err of graphQLErrors) {

                switch (err.extensions?.code) {
                    
                    case "UNAUTHENTICATED" :
                        console.log('aa')
                        return fromPromise(
                            getNewToken().catch((error) => {
                                localStorage.clear();
                                // Handle token refresh errors e.g clear stored tokens, redirect to login
                                return;
                            })
                        )
                            .filter((value) => Boolean(value))
                            .flatMap(({accessToken, refreshToken}) => {

                                const oldHeaders = operation.getContext().headers;
                                // modify the operation context with a new token
                                operation.setContext({
                                    headers: {
                                        ...oldHeaders,
                                        authorization: `Bearer ${accessToken}`,
                                    },
                                });

                                // retry the request, returning the new observable
                                return forward(operation);
                            });
                   

                }
            }
        }
    }
);



const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      authorization: localStorage.getItem("AUTHORIZATION") ? `Bearer ${localStorage.getItem("AUTHORIZATION")}` : "",
    },
  };
});




const client = new ApolloClient({
  link: ApolloLink.from([errorLink,authLink, httpLink]),
})

 

Проблема в следующем:
он не возвращает данные в мой запрос на использование после успешного обновления токенов

2 запрос

4 запрос

кстати, это делает еще один неудачный запрос, я не знаю, почему

3 запрос

Комментарии:

1. Вам нужно использовать useLazyQuery . Например. у вас есть компонент, в котором вы вызываете useQuery, затем, как только компонент монтируется, запускается useQuery и данные извлекаются с сервера. Но если вы используете useLazyQuery в этом компоненте вместо useQuery, запрос не выполняется и данные не извлекаются при монтировании компонента. Вместо этого вы можете выполнить запрос в соответствии с вашими требованиями, скажем, после получения маркера обновления или при нажатии кнопки.

Ответ №1:

Вы можете использовать ссылку повторить попытку, чтобы снова запустить запрос.

Вы должны связать свои ссылки таким образом, чтобы ссылка на повторную попытку была самой внешней ссылкой, чтобы вы могли дождаться, пока ваша ссылка на ошибку получит токен. Ознакомьтесь с пользовательскими стратегиями, здесь вы можете отреагировать на определенный код состояния в объекте ошибки или прослушать пользовательское свойство, которое ссылка на ошибку может прикрепить к operation объекту. Таким образом, вы даже можете предотвратить повторную выборку, если обновление токена не удалось (например, из-за того, что время ожидания токена повторной выборки также истекло).

Все ссылки также имеют открытый исходный код, поэтому, если их объединение в цепочку на самом деле не работает для вас, вы также можете создать свою собственную ссылку для повторной выборки повторной попытки, объединив код обеих ссылок.