【问题标题】:GraphQL redirect when resolver throws error解析器抛出错误时的 GraphQL 重定向
【发布时间】:2017-05-07 23:12:37
【问题描述】:

我正在使用 graphql-server-express 构建一个使用 REST API 的 GraphQL 服务器。

我的情况是,当用户未通过身份验证访问资源时,REST 调用可能会返回 301 或 401 状态代码。我正在使用在客户端上设置并在解析 GraphQL 查询时转发到 REST API 的 cookie。

当发生此类错误时,是否可以向客户端发送 301 重定向以响应对 GraphQL 端点的调用?

我在formatError 中尝试过类似res.sendStatus(301) … 的方法,但效果不佳,因为graphql-server-express 会在此之后尝试设置标题。

我也尝试过用类似这样的方式来短路graphqlExpress 中间件:

export default graphqlExpress((req, res) => {
  res.sendStatus(301);
  return;
});

当客户端收到正确的结果时,服务器仍然会打印错误(在这种情况下 TypeError: Cannot read property 'formatError' of undefined - 很可能是因为中间件收到了空选项)。

有什么好方法可以让它工作吗?谢谢!

【问题讨论】:

  • 重定向到哪里? GraphQL 中的重定向实际上没有意义。如果客户端发送一个带有两个根节点的查询,一个成功(无需登录),一个失败,你发送什么,300 还是 200?
  • 如果至少一个字段失败,在我的情况下应该发送重定向。
  • 但是graphql查询是由JS代码执行的,不是浏览器直接执行的,jsut发送重定向并不意味着浏览器会加载登录页面。您的 graphql 客户端需要检测此响应代码,然后对其进行硬编码以在它发生时执行某些操作。
  • 最好在您的“json 错误”响应中发送相同的信息并让您的客户对其做出反应。更改响应代码对您没有任何帮助。
  • 你说得对。我以某种方式认为 301 状态代码会导致客户端更改其位置,但是例如fetch 只是跟随重定向并将加载该资源。所以可能最好的方法就像你提到的在我的解析器中抛出一个自定义重定向错误,客户端知道如何处理 - 也许使用apollo client afterware (在链接的示例中,他们实际上是使用响应的状态代码来做出反应注销)

标签: node.js redirect graphql apollo-server


【解决方案1】:

在graphql解析器中处理重定向的另一种方法是将“状态”设置为302(重定向的http状态代码)和响应中的“位置”,如下面的代码,

this.Query = {
  downloadFile: (parent, { url }, { res }) => {
    res.status(302);
    res.set('Location', url);

    return;
}

【讨论】:

    【解决方案2】:

    这是我如何实现的。

    在服务器端:

    // Setup
    export default class UnauthorizedError extends Error {
      constructor({statusCode = 401, url}) {
        super('Unauthorized request to ' + url);
        this.statusCode = statusCode;
      }
    }
    
    // In a resolver
    throw new UnauthorizedError({url});
    
    // Setup of the request handler
    graphqlExpress(async (req, res) => ({
      schema: ...,
      formatError(error) {
        if (error.originalError instanceof UnauthorizedError) {
          res.status(error.originalError.statusCode);
          res.set('Location', 'http://domain.tld/login');
        } else {
          res.status(500);
        }
    
        return error;
      },
    });
    

    在客户端:

    const networkInterface = createNetworkInterface();
    
    networkInterface.useAfter([{
      applyAfterware({response}, next) {
        if ([401, 403].includes(response.status)) {
          document.location = response.headers.get('Location');
        } else {
          next();
        }
      }
    }]);
    

    在 Apollo Client 2.0 中,您可能可以在客户端使用 apollo-link-error

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-23
      • 2017-07-15
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 2019-12-28
      相关资源
      最近更新 更多