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

Vercel部署的Next.js前端连接AWS EC2(Node+Express)后端时持续出现CORS错误的解决求助

Vercel部署的Next.js前端连接AWS EC2(Node+Express)后端时持续出现CORS错误的解决求助

我现在遇到个头疼的问题:把Next.js前端部署在Vercel,Node+Express后端放在AWS EC2上(已经搭了Nginx),明明配置了CORS但还是一直报跨域错误。我已经给后端绑定了api.neuera.in的域名,可前端请求就是被跨域政策拦截,想问问大家有没有什么排查方向,是不是Nginx那边还需要加什么规则,或者我哪里的配置漏了?

后端CORS及相关中间件配置

const allowedOrigins = [
  // "http://localhost:3000",
  "https://neuera.in",
  "https://www.neuera.in",
];

const corsOptions = {
  origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
    // Allow requests with no origin (mobile apps, Postman, server-to-server)
    if (!origin) {
      console.log("✅ No origin header - allowing request");
      return callback(null, true);
    }
    if (allowedOrigins.includes(origin)) {
      console.log(`✅ CORS allowed for origin: ${origin}`);
      callback(null, true);
    } else {
      console.warn(`❌ CORS blocked origin: ${origin}`);
      callback(new Error(`CORS policy violation: Origin ${origin} not allowed`));
    }
  },
  credentials: true,
  optionsSuccessStatus: 200,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
  allowedHeaders: [
    'Origin',
    'X-Requested-With',
    'Content-Type',
    'Accept',
    'Authorization',
    'Cache-Control',
    'X-API-Key',
    'Access-Control-Allow-Headers',
    'Access-Control-Allow-Origin'
  ],
  preflightContinue: false
};

// Apply CORS BEFORE other middleware
app.use(cors(corsOptions));

// Security headers (configure after CORS)
app.use(helmet({
  crossOriginResourcePolicy: { policy: "cross-origin" },
  contentSecurityPolicy: false,
  crossOriginEmbedderPolicy: false
}));

前端RTK Query配置片段

export const api = createApi({
  baseQuery: customBaseQuery,
  reducerPath: "api",
  tagTypes: ["Projects", "Tasks", "Users", "Teams"],
  endpoints: (build) => ({
    getAuthUser: build.query({
      queryFn: async (_, _queryApi, _extraoptions, fetchWithBQ) => {
        try {
          const user = await getCurrentUser();
          const session = await fetchAuthSession();
          if (!session) {
            return {
              error: { status: 401, data: 'No session found' } as FetchBaseQueryError,
            };
          }
          const { userSub } = session;
          const userDetailsResponse = await fetchWithBQ(`users/${userSub}`);
          const userDetails = userDetailsResponse.data as User;
          if (userDetailsResponse.error) {
            return { error: userDetailsResponse.error };
          }
          return { data: { user, userSub, userDetails } };
        } catch (error: unknown) {
          const errorMessage = error instanceof Error ? error.message : "Could not fetch user data";
          return {
            error: { status: 'CUSTOM_ERROR', data: errorMessage } as FetchBaseQueryError,
          };
        }
      },
    }),
    // 其他端点...
  }),
});

排查与解决建议

  • 第一优先级:检查allowedOrigins是否包含Vercel前端域名
    你当前的allowedOrigins里只有neuera.in和www.neuera.in,但Vercel部署的前端域名应该是类似https://your-project-name.vercel.app(或者你绑定的自定义域名),必须把这个域名加到allowedOrigins数组里,否则后端会直接拦截请求。

  • 检查Nginx配置是否正确转发请求并处理跨域头
    因为你用了Nginx反向代理,可能Nginx的配置会覆盖或拦截Express返回的CORS头,建议在Nginx的server块里添加以下配置:

    server {
      listen 443 ssl;
      server_name api.neuera.in;
    
      # 处理OPTIONS预请求
      if ($request_method = OPTIONS) {
          add_header Access-Control-Allow-Origin $http_origin always;
          add_header Access-Control-Allow-Credentials true always;
          add_header Access-Control-Allow-Methods 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
          add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, X-API-Key' always;
          return 204;
      }
    
      # 转发到Express服务(假设Express跑在3000端口)
      location / {
          proxy_pass http://localhost:3000;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
    
          # 确保跨域头正确传递
          add_header Access-Control-Allow-Origin $http_origin always;
          add_header Access-Control-Allow-Credentials true always;
      }
    }
    

    注意:always关键字很重要,确保即使返回非200状态码也会发送这些头。

  • 验证前端RTK Query的customBaseQuery是否携带凭证
    后端配置了credentials: true,前端必须在请求中携带凭证(cookie、HTTP认证等)。检查你的customBaseQuery是否配置了credentials: 'include',比如:

    const customBaseQuery = async (args, api, extraOptions) => {
      const result = await fetchBaseQuery({
        baseUrl: 'https://api.neuera.in',
        credentials: 'include', // 必须加这个
        // 其他配置...
      })(args, api, extraOptions);
      return result;
    };
    
  • 用工具测试预请求是否正常
    用curl发送OPTIONS请求测试后端响应:

    curl -X OPTIONS https://api.neuera.in/users/123 \
      -H "Origin: https://your-vercel-domain.vercel.app" \
      -H "Access-Control-Request-Method: GET" \
      -H "Access-Control-Request-Headers: Authorization" \
      -v
    

    查看响应头是否包含Access-Control-Allow-Origin: https://your-vercel-domain.vercel.app和Access-Control-Allow-Credentials: true,如果没有,说明后端或Nginx的配置有问题。

  • 检查Helmet配置是否有隐藏冲突
    虽然你已经关闭了部分Helmet默认配置,但可以临时注释掉Helmet中间件,测试是否还报CORS错误,排除Helmet的影响。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:43:03