React Apollo Link-兑现承诺后如何转发操作?

时间:2019-09-17 23:32:32

标签: reactjs react-apollo apollo-client

因此,我弄清楚了如何设置中间件来处理我的身份验证令牌,以及在需要时获取新令牌。问题是,在解决承诺后,在没有设置适当的标头的情况下转发该操作,导致存在另一个可能未经身份验证的调用的情况。我觉得这里的技巧很简单,但是我似乎无法弄清楚。有没有办法将承诺中的结果返回到包含的函数中?关于这一点,我还没有找到太多的运气,但是也许还有另一种方法。这是设置我的中间件和Apollo客户端的代码:

const authLink = new ApolloLink((operation, forward) => {
  operation.setContext(({ headers = {} }) => {
    const token = localStorage.getItem('token');
    const tokenExp = token ? decodeJWT(token).exp : null;
    const currentTime = Date.now() / 1000;

    if(token && tokenExp >= currentTime) {
      // Check if token is expired. If so, get a new one and THEN
      // move forward
      headers = { ...headers,authorization: token ? `Bearer ${token}` : "", };
      return { headers };
    } else {

    // TODO: This would be replaced with the token service that actually
    // takes an expired token and sends back a valid one
    return fetch('http://localhost:4000/topics', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          query: `mutation LOGIN_USER(
            $email: String
            $password: String!
          ) {
            login(email: $email, password: $password) {
              id
              token
            }
          }
        `,
          variables: {
            email: "test@test.com",
            password: "test"
          }
        }),
      }).then(response => {
        return response.json()
      })
      .then(({ data: { login: { token } }}) => {
        // Put updated token in storage
        localStorage.setItem('token', token);
        headers = { ...headers,authorization: token ? `Bearer ${token}` : "", };
        return { headers };
      });
    }
  });
  return forward(operation);
});


/**
 * Setup the URLs for each service
 */
const httpTopicsServiceLink = createHttpLink({
  uri: 'http://localhost:4000/topics',
});

/**
 * Create the client instance for each GraphQL server URL
 */
export const TopicsClient = new ApolloClient({
  link:authLink.concat(httpTopicsServiceLink),
  cache: new InMemoryCache(),
});

1 个答案:

答案 0 :(得分:0)

您可以返回自己的Promise,该Promise将使用标题或获取请求中的另一个Promise进行解析:

const authLink = new ApolloLink(async (operation, forward) => {
  return await operation.setContext(({ headers = {} }) => {
    const token = localStorage.getItem('token');
    const tokenExp = token ? decodeJWT(token).exp : null;
    const currentTime = Date.now() / 1000;

    return new Promise((resolve, reject) => {
        if(token && tokenExp >= currentTime) {
      // Check if token is expired. If so, get a new one and THEN
      // move forward
      headers = { ...headers,authorization: token ? `Bearer ${token}` : "", };
      resolve({ headers });
    } else {

    // TODO: This would be replaced with the token service that actually
    // takes an expired token and sends back a valid one
    resolve(fetch('http://localhost:4000/topics', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          query: `mutation LOGIN_USER(
            $email: String
            $password: String!
          ) {
            login(email: $email, password: $password) {
              id
              token
            }
          }
        `,
          variables: {
            email: "test@test.com",
            password: "test"
          }
        }),
      }).then(response => {
        return response.json()
      })
      .then(({ data: { login: { token } }}) => {
        // Put updated token in storage
        localStorage.setItem('token', token);
        headers = { ...headers,authorization: token ? `Bearer ${token}` : "", };
        return { headers };
      }));
    }
    });

  }).then(res => {
    return forward(operation);
  });
});

无法测试,所以我可能错过了一些东西,但这应该确保请求在转发之前完成。