Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

获取egg-graphql中业务代码抛出的异常 #3064

Open
nigelvon opened this issue Sep 30, 2018 · 12 comments
Open

获取egg-graphql中业务代码抛出的异常 #3064

nigelvon opened this issue Sep 30, 2018 · 12 comments
Assignees
Labels

Comments

@nigelvon
Copy link

发现graphql请求触发的业务逻辑所抛出的异常都被捕获了,不知道如何获取Error对象,控制台和相关日志找了一圈也没看到。
有什么办法能够获取这些Error么?

@ghost
Copy link

ghost commented Oct 24, 2018

使用try……catch也无法捕获吗?请问目前你的代码是?

@nigelvon
Copy link
Author

单独对出错代码try catch是可以捕获的,想要在外层统一拦截。

@SingleMai
Copy link

萌新同问,如果想要在做统一封装拦截有什么方案吗。现在发现graphql的报错不会走到egg-error的拦截中,(即使是代码层面的报错)也会被统一拦截到了前端,只能一个个去加try...catch。
稍微看了一下源码,好像是有统一做try{}catch{}然后返回给前端,请问能否在这里切入提供一个函数方便自定义处理呢。

@logzh
Copy link

logzh commented Dec 19, 2018

如果是egg-graphql 2.0以下版本,可以将插件中间件复制到项目下修改,覆盖插件里的中间件,具体修改配置graphqlKoa时带上formatError,在formatError中做错误的统一处理。
2.0+之后,同样的方式不灵了因为graphqlKoa api修改了,formatError只能在定义server的时候定义。

@SingleMai
Copy link

首先感谢大佬回复,不过这里提到的formateError只能在定义server的时候定义能否具体描述一下呢。我看源码里面是直接引用了graphql的方法来进行报错,好像并没有提供出定义的位置...以及这样做怎样和resetApi时的报错中间件能结合起来使用也是比较疑惑的点

@logzh
Copy link

logzh commented Dec 20, 2018

@SingleMai

egg-egg-graphql 1.x版本

egg-egg-graphql 1.x版本对应的apollo-server-koa是1.x,下面是apollo-server-koa 1.x的官方demo:
https://github.com/apollographql/apollo-server/blob/v1.4.0/packages/apollo-server-koa/README.md

import koa from 'koa'; // koa@2
import koaRouter from 'koa-router';
import koaBody from 'koa-bodyparser';
import { graphqlKoa } from 'apollo-server-koa';

const app = new koa();
const router = new koaRouter();
const PORT = 3000;

// koaBody is needed just for POST.
app.use(koaBody());

router.post('/graphql', graphqlKoa({ schema: myGraphQLSchema }));
router.get('/graphql', graphqlKoa({ schema: myGraphQLSchema }));

app.use(router.routes());
app.use(router.allowedMethods());
app.listen(PORT);

如果要增加错误统一处理:

router.post('/graphql', graphqlKoa({ schema: myGraphQLSchema, formateError: func... }));

egg-egg-graphql 1.x插件中间件的使用是
https://github.com/eggjs/egg-graphql/blob/1.3.0/app/middleware/graphql.js

return graphqlKoa({
        schema: app.schema,
        context: this,
      })(this);

这样没有办法直接传 formateError 参数。

所以我才说

如果是egg-graphql 2.0以下版本,可以将插件中间件复制到项目下修改,覆盖插件里的中间件,具体修改配置graphqlKoa时带上formatError,在formatError中做错误的统一处理。

egg-egg-graphql 2.x版本

egg-egg-graphql 2.x版本对应的apollo-server-koa是2.x,下面是apollo-server-koa 2.x的官方demo:
https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-koa/README.md

const Koa = require('koa');
const { ApolloServer, gql } = require('apollo-server-koa');

// Construct a schema, using GraphQL schema language
const typeDefs = gql`
  type Query {
    hello: String
  }
`;

// Provide resolver functions for your schema fields
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};

const server = new ApolloServer({ typeDefs, resolvers });

const app = new Koa();
server.applyMiddleware({ app });

app.listen({ port: 4000 }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`),
);

如果要增加错误统一处理:

const server = new ApolloServer({ typeDefs, resolvers, formateError: func ... });

egg-egg-graphql 2.x插件中间件的使用是
https://github.com/eggjs/egg-graphql/blob/2.3.0/app/middleware/graphql.js

return graphqlKoa({
        schema: app.schema,
        context: this,
      })(this);

这里的 graphqlKoa 即使传入 formateError 参数也没办法了。

对于“怎样和resetApi时的报错中间件能结合起来使用”
我们这边没有这样的场景,我们是的做了个graphql单独的服务,graphql服务的后面是后台接口等(包括其他数据来源),graphql服务提供服务给前台服务端或前台客户端。

@SingleMai
Copy link

感谢回复, so噶 抱歉最近有点太忙了 一直没上来看。大佬解释得非常清晰,算是理清了很多疑惑非常感谢!!

@jtyjty99999
Copy link
Member

我把这个 formateError 透出一下

@jtyjty99999
Copy link
Member

eggjs/egg-graphql#24 跟进

@michaellyu
Copy link

eggjs/egg-graphql#24 一直没有进展吗? @jtyjty99999

@wushanchao
Copy link

wushanchao commented Jul 17, 2019

egg中有两个地方可以捕捉egg-graphql的解析错误或者内部错误。

  1. 中间件
exports.middleware = ['errorHandler','graphql'];
  1. 另一个是框架层面的onerror。
exports.onerror = {
  all(err, ctx){
    if(ctx.request.url.indexOf('/graphql')>-1 && ctx.response.status !== 200){
      // console.log('捕获住了gql错误');
      ctx.set({
        "Content-Type": "application/json"
      });
      ctx.status = 200;
      ctx.body = JSON.stringify({
        data:null,
        message:'gql解析错误',
        success: false
      });
    }
    else{
      ctx.status = 400;
      ctx.body = 'error';
    }
    
  }
}

@Beiluola
Copy link

我很高兴自己解决了这个问题,在这里分享一下。

标题中说捕获graphql中业务代码的异常,而自己的业务代码都是写在resolver中的,也就是说,如果可以在resolver执行前首先执行类似 try{ } catch(err){ } 这样的代码,把resolver的实际执行放在 try{ } 代码段中,即可实现捕捉graphql异常。

所有resolver都可以在app.schema中获取到,那么就可以实现上述所说。

不仅如此,我还把它扩展成了类似中间件一样的机制,这样就可以有更多的玩法。

请参考下面项目的README介绍中的 resolver中间件 章节

https://github.com/beiluola/glacier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants