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

