Reactjs 反应阿波罗链接-承诺解决后如何推进操作?

Reactjs 反应阿波罗链接-承诺解决后如何推进操作?,reactjs,react-apollo,apollo-client,Reactjs,React Apollo,Apollo Client,因此,我想出了如何设置一个中间件来处理我的身份验证令牌,并在需要时获取新的身份验证令牌。问题在于,这里存在一种边缘情况,即在承诺得到解决后,操作在未设置正确的头的情况下被转发,导致另一个可能未经验证的调用。我觉得这里的诀窍很简单,但我似乎不明白。有没有一种方法可以将承诺的结果返回到所包含的函数?我在这方面运气不太好,但也许还有别的办法。以下是设置我的中间件和Apollo客户端的代码: const authLink = new ApolloLink((operation, forward) =&g

因此,我想出了如何设置一个中间件来处理我的身份验证令牌,并在需要时获取新的身份验证令牌。问题在于,这里存在一种边缘情况,即在承诺得到解决后,操作在未设置正确的头的情况下被转发,导致另一个可能未经验证的调用。我觉得这里的诀窍很简单,但我似乎不明白。有没有一种方法可以将承诺的结果返回到所包含的函数?我在这方面运气不太好,但也许还有别的办法。以下是设置我的中间件和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(),
});

您可以返回自己的承诺,该承诺将通过标头或获取请求中的另一个承诺进行解析:

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);
  });
});

无法测试这一点,因此我可能遗漏了一些内容,但这应该确保在转发之前完成请求。

如果
setContext
返回承诺,您不能添加
然后
语句并转发到那里吗?这是什么意思?我尝试向操作中添加一个.then,但我收到错误消息,告诉我未定义的
无法读取属性'then
:/感谢您的响应,但不幸的是,我收到未定义的
无法读取属性'then'。我曾尝试过类似的方法,将整个operation.setContext包装在一个Promise中。虽然我认为函数必须返回一个可观察的,而不是简单地调用
forward(operation)
hmmmedit:我误解了。如果Apollo链接回调可以是异步的?你可以等待
setContext。更新我的答案,值得一试!谢谢你的努力?我在胡闹,然后尝试了你的版本,我得到了
转发(…)。订阅不是一个函数
错误哈哈。我在做别的事情时也犯了同样的错误。我甚至试着用
from
from
rxjs
将整个东西包装起来,但没有成功:P