NextJS自定义服务器执行npm run build构建后出现CORS错误
我来帮你梳理下问题根源和解决方案,你遇到的情况其实是两个关键点没处理好:生产环境下的代理缺失,以及CORS配置的细节冲突。
问题核心分析
开发vs生产的代理差异:你的自定义服务器代码里,只有
isDevelopment为true时才启用了http-proxy-middleware代理。开发时前端请求/api会被转发到后端5002端口,属于同域请求(都是从3000端口发起),所以Cookie能正常传递,也不会有CORS问题。但生产构建后,代理没启用,前端直接请求localhost:5002,这就产生了跨域,加上你开启了withCredentials: true,而后端如果配置的是Access-Control-Allow-Origin: *,就会触发浏览器的CORS拦截规则——带凭证的请求不允许使用通配符源。CORS配置的冲突:当请求携带凭证(Cookie、HTTP认证等)时,后端的CORS必须满足两个条件:
Access-Control-Allow-Origin不能是*,必须是前端的具体源(比如http://localhost:3000)- 必须设置
Access-Control-Allow-Credentials: true
解决方案一:生产环境启用代理(推荐)
既然你用了自定义服务器,最好保持开发和生产环境的请求一致,都通过代理转发,这样从根源上避免跨域问题。修改你的server.js代码,去掉代理的环境判断:
const express = require('express'); const next = require('next'); const { createProxyMiddleware } = require('http-proxy-middleware'); const port = 3000; const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); const apiPaths = { '/api': { target: 'http://localhost:5002', pathRewrite: { '^/api': '/api', }, changeOrigin: true, // 可选:如果后端需要识别真实客户端IP,开启此项 // xfwd: true }, }; app .prepare() .then(() => { const server = express(); // 移除环境判断,生产环境也启用代理 server.use('/api', createProxyMiddleware(apiPaths['/api'])); server.all('*', (req, res) => { return handle(req, res); }); server.listen(port, (err) => { if (err) throw err; console.log(`> Ready on http://localhost:${port}`); }); }) .catch((err) => { console.log('Error:::::', err); });
修改后,生产环境下前端请求/api会被服务器转发到5002端口,属于同域请求,你甚至可以把Axios里的withCredentials: true去掉(因为不需要跨域传凭证了),Cookie会自动在服务器转发时传递给后端。
解决方案二:正确配置后端CORS(不推荐,仅当无法使用代理时)
如果一定要让前端直接请求5002端口,需要调整后端的CORS配置:
后端Express的cors配置修改
const cors = require('cors'); // 配置允许的源,生产环境要换成你的实际域名 const allowedOrigins = ['http://localhost:3000']; const corsOptions = { origin: function (origin, callback) { // 允许没有origin的请求(比如Postman)或者在允许列表里的源 if (!origin || allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, credentials: true // 必须设置为true,允许传递凭证 }; app.use(cors(corsOptions));
前端Axios配置保持
确保你的Axios请求里的withCredentials: true保留,同时请求的URL要正确指向5002端口(或者你的后端域名)。
额外注意点
- 生产环境部署时,记得把
allowedOrigins里的localhost:3000换成你的实际前端域名,比如https://your-app.com。 - 如果你用了Next.js的SSG/ISR,要确保获取数据的逻辑在
getServerSideProps里执行,这样服务器端请求后端不会有跨域问题,也能直接传递Cookie。
内容的提问来源于stack exchange,提问作者Abu Sayeed Mondal

