You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:47:48