Angular 阿波罗测角系统中令牌刷新错误

Angular 阿波罗测角系统中令牌刷新错误,angular,graphql,apollo,apollo-angular,Angular,Graphql,Apollo,Apollo Angular,我正在使用apollo angular构建一个前端应用程序。在我的应用程序中,我使用JWT身份验证系统和一个短生命周期访问令牌和一个长生命周期刷新令牌(它们在一个仅HTTP的cookie中传输,而不是存储在HTTP头中的begin) 当我运行我的应用程序时,我可以成功登录,但当访问令牌过期时,我会出现以下错误,并且在浏览器上看不到任何内容。 错误:网络错误:无法读取未定义时的属性“刷新”错误 我的代码如下: 图形QLMODule(在AppModule中导入)(部件基于) 编写这些代码是为了实现以

我正在使用apollo angular构建一个前端应用程序。在我的应用程序中,我使用JWT身份验证系统和一个短生命周期访问令牌和一个长生命周期刷新令牌(它们在一个仅HTTP的cookie中传输,而不是存储在HTTP头中的begin)

当我运行我的应用程序时,我可以成功登录,但当访问令牌过期时,我会出现以下错误,并且在浏览器上看不到任何内容。
错误:网络错误:无法读取未定义时的属性“刷新”错误

我的代码如下:

图形QLMODule(在AppModule中导入)(部件基于)

编写这些代码是为了实现以下应用程序流:

  • 用户尝试登录(通过graphql发送身份验证信息)
  • 后端服务器将访问令牌和刷新令牌发送到前端应用程序
  • 用户尝试发送一个graphql查询,其结果根据用户是否经过身份验证而改变(未经身份验证的用户也可以看到查询结果)
  • 前端应用程序检查用户是否登录以及访问令牌是否过期
  • 如果用户已登录且访问令牌已过期,前端应用程序将发送带有graphql变异的刷新令牌,以在原始查询之前获取新的访问令牌
  • 在发送回新的访问令牌后,将发送原始查询
  • 我用的是Angular8和apollo angular 1.8.0

    我对Angular很陌生,所以我可能错过了一些非常简单的东西;(

    提前感谢您!

    不确定此问题的确切解决方案,但您可以尝试使用
    catchError
    RxJS运算符处理
    refresh()
    方法中的错误-也许您需要重试,或者您可以查看有关错误的更多详细信息并进行跟踪

    从'rxjs/operators'导入{catchError,map};
    从'rxjs'导入{of};
    //...
    @注射的({
    providedIn:'根',
    })
    导出类身份验证服务{
    //...
    刷新(){
    归还这个,阿波罗,变异({
    突变:刷新
    }).烟斗(
    地图((结果:任意)=>{
    如果(结果){
    //...
    }
    否则{
    console.warn(“出现错误。有关详细信息,请参阅上面的输出。”)
    }
    }),
    catchError((错误:error)=>{
    //处理此错误,可能会重试
    console.log(错误和错误消息);
    返回(空);
    })
    );
    }
    //...
    }
    
    感谢您的回答。我尝试了您的解决方案(为了简单起见,我通过
    console.log(err);return of()
    处理了错误),但仍然出现了错误。由于在
    refresh()中没有出现错误,所以它无法正常工作
    但在Apollo.Odd中,Apollo确实应该发送错误以进行处理-您是否尝试在()的
    中返回null,然后在map函数中处理null?(更新了我的答案,提供了更多详细信息)感谢您的回复和修改的答案。我尝试了您的解决方案。在我的控制台中,我看到一个日志,上面写着
    [网络错误]:TypeError:无法读取未定义的属性“refresh”和一个表示相同内容的错误,并且我在浏览器中看不到任何内容。抱歉,我不太了解Apollo。可能值得在git上查看他们的支持/报告问题-如果
    catchError
    b没有捕获到该错误,他们会觉得这可能是一个未经处理的错误锁。也就是说,显然是你的代码中的某些东西触发了它,所以我能建议的最好方法是删除一些位,直到错误消失——这样你就可以确定导致问题的代码的确切行,也许这会给你一些更深入的见解,或者问社区一个更具体的问题?抱歉,我不能再多说了e很有帮助!不要抱歉,我真的很感谢你迄今为止为我所做的一切努力。我实际上是在问自己是否要在《阿波罗天使号》(apollo angular)GitHub问题上发布这个问题。我会在那里寻求帮助。再次非常感谢!这是否回答了你的问题@ganesh045谢谢你的评论。这就是我提到的问题在我的问题上我同意。
    import { NgModule } from '@angular/core';
    import { HttpClientModule } from '@angular/common/http';
    
    import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
    import { InMemoryCache } from 'apollo-cache-inmemory';
    import { HttpLinkModule, HttpLink } from 'apollo-angular-link-http';
    import { ApolloLink, Observable } from 'apollo-link';
    import { onError } from 'apollo-link-error';
    
    import { AuthService } from '../account/auth/auth.service';
    import { environment } from '../../environments/environment';
    
    const promiseToObservable = (promise: Promise<any>) =>
      new Observable((subscriber: any) => {
        promise.then(
          value => {
            if (subscriber.closed) {
              return;
            }
            subscriber.next(value);
            subscriber.complete();
          },
          err => subscriber.error(err)
        );
      });
    
    const errorLink = onError(({ graphQLErrors, networkError }) => { // need help on linking this with graphql module
      if (graphQLErrors) {
        graphQLErrors.map(({ message, locations, path }) =>
          console.log(
            `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
          ),
        );
      }
    
      if (networkError) { console.log(`[Network error]: ${networkError}`); }
    });
    
    export function createApollo(httpLink: HttpLink, authService: AuthService) {
      const basicLink = httpLink.create({
        uri: environment.apiUrl,
        withCredentials: true,
      });
    
      const authMiddleware = new ApolloLink((operation, forward) => {
        if (operation.operationName !== 'RefreshToken') {
          if (localStorage.getItem('loginStatus') && localStorage.getItem('loginStatus') === '1') {
            const nowtime = new Date();
            const accessExpiresIn = new Date(localStorage.getItem('accessExpiresIn'));
            const refreshExpiresIn = new Date(localStorage.getItem('refreshExpiresIn'));
            if (accessExpiresIn <= nowtime && refreshExpiresIn > nowtime) {
              return promiseToObservable(authService.refresh().toPromise()).flatMap(() => forward(operation));
            } else if (accessExpiresIn <= nowtime && refreshExpiresIn <= nowtime) {
              return promiseToObservable(authService.logout().toPromise()).flatMap(() => forward(operation));
            } else {
              return forward(operation);
            }
          } else {
            return forward(operation);
          }
        } else {
          return forward(operation);
        }
      });
    
      const link = ApolloLink.from([errorLink, authMiddleware, basicLink]);
      const cache = new InMemoryCache();
    
      return {
        link,
        cache,
      };
    }
    
    @NgModule({
      imports: [
        HttpClientModule,
        ApolloModule,
        HttpLinkModule
      ],
      exports: [
        ApolloModule,
        HttpLinkModule
      ],
      providers: [
        {
          provide: APOLLO_OPTIONS,
          useFactory: createApollo,
          deps: [HttpLink, AuthService],
        },
      ],
    })
    export class GraphQLModule { }
    
    import { map } from 'rxjs/operators';
    
    import { Injectable } from '@angular/core';
    import { Router } from '@angular/router';
    
    import { Apollo } from 'apollo-angular';
    import gql from 'graphql-tag';
    
    const login = gql`
      mutation Login($username: String!, $password: String!) {
        getToken (
          email: $username,
          password: $password
        ) {
          payload
          refreshExpiresIn
        }
      }
    `;
    
    const refresh = gql`
      mutation RefreshToken {
        refreshToken {
          payload
          refreshExpiresIn
        }
      }
    `;
    
    const logout = gql`
      mutation Logout {
        deleteTokenCookie {
          deleted
        }
        deleteRefreshTokenCookie {
          deleted
        }
      }
    `;
    
    @Injectable({
      providedIn: 'root',
    })
    export class AuthService {
    
      constructor(
        public router: Router,
        private apollo: Apollo,
      ) { }
    
      saveExpiresIn(accessExpiresIn: number, refreshExpiresIn: number) {
        const accessExpiresIn = new Date(accessExpiresIn * 1000);
        const refreshExpiresIn = new Date(refreshExpiresIn * 1000);
        localStorage.setItem('accessExpiresIn', accessExpiresIn.toString());
        localStorage.setItem('refreshExpiresIn', refreshExpiresIn.toString());
      }
    
      login(username: string, password: string) {
        return this.apollo.mutate({
          mutation: login,
          variables: {
            username,
            password,
          },
        }).pipe(map((result: any) => {
          this.saveExpiresIn(
            result.data.tokenAuth.payload.exp,
            result.data.tokenAuth.refreshExpiresIn
          );
          localStorage.setItem('loginStatus', String(1));
    
          return result;
        }));
      }
    
      refresh() {
        return this.apollo.mutate({
          mutation: refresh
        }).pipe(map((result: any) => {
          this.saveExpiresIn(
            result.data.refreshToken.payload.exp,
            result.data.refreshToken.refreshExpiresIn
          );
    
          return result;
        }));
      }
    
      logout() {
        return this.apollo.mutate({
          mutation: logout
        }).pipe(map((result: any) => {
          localStorage.removeItem('loginStatus');
          localStorage.removeItem('accessExpiresIn');
          localStorage.removeItem('refreshExpiresIn');
    
          return result;
        }));
      }
    }