Node+TypeScript+GraphQL+Apollo跨域问题:配置疑误致请求失败
解决前后端分离CORS错误(Node/TypeScript/Apollo + React)
问题根源
你的代码存在两个关键冲突:
- 全局Express中间件使用了
app.use(cors())(默认允许所有源*),但你同时开启了credentials: true,浏览器规定当凭据模式为include时,Access-Control-Allow-Origin不能是通配符*,必须是具体域名。 - 虽然你配置了
corsOptions并通过app.options('*', cors(corsOptions))处理了预检请求,但实际业务请求的响应头被全局默认的cors()中间件覆盖,导致头信息不符合要求。
修复方案(二选一)
方案1:统一使用自定义CORS配置覆盖全局中间件
修改Express中间件配置,把默认的app.use(cors())替换为你定义好的corsOptions:
import express from 'express'; import cors from 'cors'; import { ApolloServer } from 'apollo-server-express'; import schema from '../graphql/schema'; const app = express(); const port = process.env.PORT || 4000; const whitelist = ['http://localhost:3000']; const corsOptions: cors.CorsOptions = { origin: (origin: any, callback: any) => { if (whitelist.indexOf(origin) !== -1 || !origin) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', credentials: true, optionsSuccessStatus: 204, }; // 移除默认的app.use(cors()),替换为自定义配置 app.use(cors(corsOptions)); // 保留该配置确保预检请求走正确规则 app.options('*', cors(corsOptions)); app.get('/', (req, res) => { res.send('Hello, World!'); }); const server = new ApolloServer({ schema, context: ({ req, res }) => ({ req, res, }) }); const startServer = async () => { await server.start(); server.applyMiddleware({ app, path: '/graphql', cors: false, // 让Express的CORS中间件处理 }); app.listen(port, () => { console.log(`Server is running on port ${port}`); }); }; startServer();
方案2:让Apollo Server直接处理CORS(更推荐)
不需要全局Express CORS中间件,直接在Apollo的配置里传入CORS选项,因为GraphQL请求仅走/graphql路径:
import express from 'express'; import { ApolloServer } from 'apollo-server-express'; import schema from '../graphql/schema'; const app = express(); const port = process.env.PORT || 4000; const whitelist = ['http://localhost:3000']; const corsOptions = { origin: (origin: any, callback: any) => { if (whitelist.indexOf(origin) !== -1 || !origin) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', credentials: true, optionsSuccessStatus: 204, }; app.get('/', (req, res) => { res.send('Hello, World!'); }); const server = new ApolloServer({ schema, context: ({ req, res }) => ({ req, res, }) }); const startServer = async () => { await server.start(); server.applyMiddleware({ app, path: '/graphql', cors: corsOptions, // 让Apollo直接处理CORS }); app.listen(port, () => { console.log(`Server is running on port ${port}`); }); }; startServer();
验证要点
- 确保前端请求的
credentials模式设置为include(如果用Apollo Client,需要在createHttpLink里配置credentials: 'include') - 重启后端服务后,检查请求响应头中的
Access-Control-Allow-Origin是否为http://localhost:3000,而不是*
内容的提问来源于stack exchange,提问作者BigZoo92
相关产品推荐
相关产品推荐

