GraphQL/Apollo异常:无可用Schema,文档加载无限及查询失败
我之前开发NodeJS+Apollo GraphQL项目时也碰到过几乎一模一样的问题,这种情况大概率是端点配置、跨域、Schema生成或者数据库连接这几个环节出了问题,咱们一步步来排查解决:
1. 先确认GraphQL端点与GraphiQL配置是否匹配
你的代码里用到了graphqlExpress和graphiqlExpress,首先要保证GraphiQL指向的端点和你挂载GraphQL服务的路径完全一致。比如:
// 挂载GraphQL服务到 /graphql 路径 app.use('/graphql', graphqlExpress({ schema: executableSchema })); // 配置GraphiQL,endpointURL必须和上面的路径一致 app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));
如果这里路径写错了,GraphiQL就会一直尝试请求错误的地址,导致无限加载最后报fetch失败。另外可以直接在浏览器访问http://localhost:你的端口/graphql,如果能看到类似{"errors":[{"message":"Must provide query string"}]}的响应,说明端点本身是正常的。
2. 检查跨域(CORS)问题
如果你的前端页面和GraphQL后端不在同一个域名/端口下,浏览器的同源策略会阻止请求,这是最常见的导致Failed to fetch的原因之一。解决办法是给Express添加CORS中间件:
- 先安装依赖:
npm install cors - 在代码中引入并使用:
const cors = require('cors'); // 允许所有域名跨域(开发环境可以用,生产环境建议指定具体域名) app.use(cors()); // 或者严格限制允许的前端域名 app.use(cors({ origin: 'http://localhost:3000' }));
也可以直接在GraphQL挂载时添加CORS:
app.use('/graphql', cors(), graphqlExpress({ schema: executableSchema }));
3. 验证可执行Schema是否正确生成
你的代码里只写了部分typeDefs,而且用了makeExecutableSchema,要确保typeDefs语法正确、resolver和typeDefs正确关联。比如:
// 补全你的typeDefs,注意字段类型要正确(比如name应该是String!) const typeDefs = ` type Query { users: [User] } type User { id: ID! name: String! email: String! } `; // 必须定义对应的resolver,不然查询users时会报错 const resolvers = { Query: { users: async () => { // 这里要确保User模型能正确查询数据 return await User.find(); } } }; // 生成可执行Schema const executableSchema = makeExecutableSchema({ typeDefs, resolvers });
如果typeDefs有语法错误(比如你代码里的St...应该是截断了,正确的是String),或者没写resolver,Schema加载失败会导致端点无法正常响应。
4. 排查数据库连接问题
你用到了User模型,如果数据库没连接成功,resolver里查询用户时会抛出错误,导致GraphQL端点返回500错误,前端自然会fetch失败。比如用Mongoose的话,要确保连接代码正确:
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/your-db-name', { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('数据库连接成功')) .catch(err => console.error('数据库连接失败:', err));
还可以在resolver里加错误捕获,方便排查具体问题:
users: async () => { try { return await User.find(); } catch (err) { console.error('查询用户出错:', err); throw new Error('获取用户列表失败'); } }
5. 确认服务器端口与路径无冲突
确保Express监听的端口没有被其他程序占用,比如app.listen(4000),然后访问http://localhost:4000/graphiql时路径正确。如果用了前端代理(比如Create React App的proxy配置),要保证代理指向了正确的后端端口。
内容的提问来源于stack exchange,提问作者Артем Мирошниченко

