NextJS与Apollo GraphQL集成时的CORS错误排查求助
解决NextJS + Apollo Server的CORS/CSRF错误
问题根源
- CORS配置位置错误:Apollo Server v4+ 不再将
cors作为自身构造函数的配置项,而是由对应的框架集成(这里是@as-integrations/next)处理CORS逻辑,直接在ApolloServer里加cors会触发类型错误。 - CSRF防护拦截:Apollo Server的CSRF机制会拦截不符合规范的请求,错误提示已给出两种解决方向:要么设置非指定类型的Content-Type,要么添加指定请求头。
解决方案
1. 修正CORS配置位置
将cors配置移到startServerAndCreateNextHandler的选项中,与context同级:
import { ApolloServer } from '@apollo/server'; import { startServerAndCreateNextHandler } from '@as-integrations/next'; import { applyMiddleware } from 'graphql-middleware'; import { makeExecutableSchema } from '@graphql-tools/schema'; import { getUserFromToken } from './../../../server/security/jwt'; import typeDefs from './schema'; import { resolvers } from './resolvers'; import { permissions } from './permissions'; const schema = applyMiddleware( makeExecutableSchema({ typeDefs: typeDefs, resolvers, }), permissions ); const server = new ApolloServer({ schema, includeStacktraceInErrorResponses: false, }); export default startServerAndCreateNextHandler(server, { context: async (req, res) => { const cookies = req.cookies; const token = cookies.titanAuthToken || ''; let user; if (token) { user = getUserFromToken(token); } return { req, res, user, token }; }, // CORS配置放在此处 cors: { origin: process.env.NEXT_PUBLIC_FRONTEND_URL || 'http://localhost:3000', // 建议明确指定域名,避免使用true credentials: true, methods: ['GET', 'POST', 'OPTIONS'], allowedHeaders: ['Content-Type', 'x-apollo-operation-name', 'apollo-require-preflight'], }, });
2. 处理CSRF拦截
根据错误提示,可任选一种方式解决:
- 客户端调整:确保Apollo Client发送请求时,
Content-Type设为application/json(Apollo Client默认自动配置,若有自定义请求逻辑需检查);或添加x-apollo-operation-name请求头,值为你的GraphQL操作名称。 - 服务端辅助:在上述
cors配置的allowedHeaders中包含提示要求的头信息,确保预请求(OPTIONS)能正常通过。
额外说明
- 避免使用
origin: true,建议明确指定前端域名(如开发环境的http://localhost:3000),生产环境通过环境变量配置,降低安全风险。 - 若使用Apollo Client,需确保客户端配置开启
credentials: 'include',与服务端的credentials: true对应:
// 客户端Apollo Client配置示例 const client = new ApolloClient({ uri: '/api/graphql', cache: new InMemoryCache(), credentials: 'include', });
内容的提问来源于stack exchange,提问作者Alex Sorensen
相关产品推荐
相关产品推荐

